From aab63d0aa338563e96ee98e2ee617236130faa68 Mon Sep 17 00:00:00 2001
From: Dimitar Dobrev <dpldobrev@protonmail.com>
Date: Tue, 21 Dec 2021 01:32:38 +0200
Subject: [PATCH] Generate valid C# for unresolvable base templates

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
---
 .../Generators/CSharp/CSharpSources.cs        |  6 ++--
 src/Generator/Generators/CodeGenerator.cs     | 33 ++++++++++---------
 tests/CSharp/CSharp.h                         |  3 ++
 3 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs
index b35b8449..351d113b 100644
--- a/src/Generator/Generators/CSharp/CSharpSources.cs
+++ b/src/Generator/Generators/CSharp/CSharpSources.cs
@@ -274,7 +274,7 @@ namespace CppSharp.Generators.CSharp
             WriteOpenBraceAndIndent();
 
             PushBlock(BlockKind.InternalsClass);
-            GenerateClassInternalHead();
+            GenerateClassInternalHead(new Class { Name = parentName });
             WriteOpenBraceAndIndent();
 
             // Generate all the internal function declarations.
@@ -704,7 +704,7 @@ namespace CppSharp.Generators.CSharp
             return @params;
         }
 
-        private void GenerateClassInternalHead(Class @class = null)
+        private void GenerateClassInternalHead(Class @class)
         {
             Write("public ");
 
@@ -3143,7 +3143,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
                 if (operatorParam == null)
                 {
                     WriteLine($@"fixed ({Helpers.InternalStruct}{
-                        Helpers.GetSuffixForInternal(originalFunction.Namespace)}* __instancePtr = &{
+                        Helpers.GetSuffixForInternal((Class) originalFunction.Namespace)}* __instancePtr = &{
                         Helpers.InstanceField})");
                     WriteOpenBraceAndIndent();
                 }
diff --git a/src/Generator/Generators/CodeGenerator.cs b/src/Generator/Generators/CodeGenerator.cs
index 1178f180..b96b428b 100644
--- a/src/Generator/Generators/CodeGenerator.cs
+++ b/src/Generator/Generators/CodeGenerator.cs
@@ -1303,29 +1303,30 @@ namespace CppSharp.Generators
         public static readonly string CreateInstanceIdentifier = Generator.GeneratedIdentifier("CreateInstance");
         public static readonly string GetOrCreateInstanceIdentifier = Generator.GeneratedIdentifier("GetOrCreateInstance");
 
-        public static string GetSuffixForInternal(DeclarationContext @class)
+        public static string GetSuffixForInternal(Class @class)
         {
-            if (@class == null)
-                return string.Empty;
-
-            Class template = null;
             var specialization = @class as ClassTemplateSpecialization ??
                 @class.Namespace as ClassTemplateSpecialization;
-            if (specialization != null)
-            {
-                template = specialization.TemplatedDecl.TemplatedClass;
-                if (@class != specialization)
-                    template = template.Classes.FirstOrDefault(c => c.Name == @class.Name);
-            }
 
-            if (template == null || !template.HasDependentValueFieldInLayout())
+            if (specialization == null)
                 return string.Empty;
 
-            if (specialization.Arguments.All(
-                a => a.Type.Type?.IsAddress() == true))
-                return "_Ptr";
+            Class template = specialization.TemplatedDecl.TemplatedClass;
+            if (@class != specialization)
+                template = template.Classes.FirstOrDefault(c => c.Name == @class.Name);
 
-            return GetSuffixFor(specialization);
+            if (template.HasDependentValueFieldInLayout())
+            {
+                if (specialization.Arguments.All(
+                    a => a.Type.Type?.IsAddress() == true))
+                    return "_Ptr";
+                return GetSuffixFor(specialization);
+            }
+            // HACK: Clang can't always resolve complex templates such as the base of std::atomic in msvc
+            return (from @base in @class.Bases
+                    let suffix = GetSuffixForInternal(@base.Class)
+                    where suffix.Length > 0
+                    select suffix).DefaultIfEmpty(string.Empty).First();
         }
 
         public static string GetSuffixFor(Declaration decl)
diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h
index 31552a77..4ad3b453 100644
--- a/tests/CSharp/CSharp.h
+++ b/tests/CSharp/CSharp.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "../Tests.h"
+#include <atomic>
 #include <cstdint>
 #include <vector>
 #include <limits>
@@ -224,6 +225,8 @@ public:
 private:
     Bar::Items _items;
     Bar::Items _itemsByValue;
+    std::atomic<int> atomicPrimitive;
+    std::atomic<SmallPOD> atomicCustom;
 };
 
 class DLL_API ComplexType