Browse Source

Worked around duplication of types nested in templates and forwarded.

Since all template specialisations are incomplete by default, so are classes nested in them. When such classes are also forwarded, there are two incomplete declarations with the same name and in the same scope. Our parser searches by name and completion and it can therefore not make a difference between the two. Consequently, it always returns the first type it finds even if it isn't the right one. When clang::Sema later completes the specialisations, it completes the nested types too which leads to two identical complete types in the same scope.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1017/head
Dimitar Dobrev 8 years ago
parent
commit
caacaa841f
  1. 5
      src/AST/Class.cs
  2. 13
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 38
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  4. 2
      src/Generator/Passes/CheckIgnoredDecls.cs
  5. 2
      src/Generator/Passes/TrimSpecializationsPass.cs
  6. 1
      tests/CSharp/CSharp.cs
  7. 8
      tests/CSharp/CSharpTemplates.h

5
src/AST/Class.cs

@ -270,6 +270,11 @@ namespace CppSharp.AST
} }
} }
public bool IsTemplate
{
get { return IsDependent && TemplateParameters.Count > 0; }
}
public override IEnumerable<Function> FindOperator(CXXOperatorKind kind) public override IEnumerable<Function> FindOperator(CXXOperatorKind kind)
{ {
return Methods.Where(m => m.OperatorKind == kind); return Methods.Where(m => m.OperatorKind == kind);

13
src/Generator/Generators/CSharp/CSharpSources.cs

@ -271,7 +271,16 @@ namespace CppSharp.Generators.CSharp
GenerateClassInternals(specialization); GenerateClassInternals(specialization);
foreach (var group in generated.SelectMany(s => s.Classes).Where( foreach (var group in generated.SelectMany(s => s.Classes).Where(
c => !c.IsIncomplete).GroupBy(c => c.Name)) // HACK: the distinction is needed to eliminate duplicate nested types
// Since all template specialisations are incomplete by default,
// so are classes nested in them.
// When such classes are also forwarded, there are two incomplete declarations
// with the same name and in the same scope. Our parser searches by name and
// completion and it can therefore not make a difference between the two.
// Consequently, it always returns the first type it finds even if it isn't the right one.
// When clang::Sema later completes the specialisations, it completes the nested
// types too which leads to two identical complete types in the same scope.
c => !c.IsIncomplete).Distinct().GroupBy(c => c.Name))
GenerateNestedInternals(group.Key, group); GenerateNestedInternals(group.Key, group);
WriteCloseBraceIndent(); WriteCloseBraceIndent();
@ -329,7 +338,7 @@ namespace CppSharp.Generators.CSharp
foreach (var nestedTemplate in @class.Classes.Where(c => !c.IsIncomplete && c.IsDependent)) foreach (var nestedTemplate in @class.Classes.Where(c => !c.IsIncomplete && c.IsDependent))
GenerateClassTemplateSpecializationInternal(nestedTemplate); GenerateClassTemplateSpecializationInternal(nestedTemplate);
if (@class.IsDependent) if (@class.IsTemplate)
{ {
if (!(@class.Namespace is Class)) if (!(@class.Namespace is Class))
GenerateClassTemplateSpecializationInternal(@class); GenerateClassTemplateSpecializationInternal(@class);

38
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -570,7 +570,7 @@ namespace CppSharp.Generators.CSharp
Helpers.InternalStruct}{Helpers.GetSuffixForInternal(@class)}"; Helpers.InternalStruct}{Helpers.GetSuffixForInternal(@class)}";
var printed = VisitDeclaration(@class).Type; var printed = VisitDeclaration(@class).Type;
if (!@class.IsDependent) if (!@class.IsTemplate)
return printed; return printed;
return $@"{printed}<{string.Join(", ", return $@"{printed}<{string.Join(", ",
@class.TemplateParameters.Select(p => p.Name))}>"; @class.TemplateParameters.Select(p => p.Name))}>";
@ -638,9 +638,7 @@ namespace CppSharp.Generators.CSharp
while (!(ctx is TranslationUnit)) while (!(ctx is TranslationUnit))
{ {
var isInlineNamespace = ctx is Namespace && ((Namespace)ctx).IsInline; AddContextName(names, ctx);
if (!string.IsNullOrWhiteSpace(ctx.Name) && !isInlineNamespace)
names.Push(ctx.Name);
ctx = ctx.Namespace; ctx = ctx.Namespace;
} }
@ -802,6 +800,38 @@ namespace CppSharp.Generators.CSharp
return templateParam == null || templateParam.Parameter != null; return templateParam == null || templateParam.Parameter != null;
} }
private void AddContextName(Stack<string> names, Declaration ctx)
{
var isInlineNamespace = ctx is Namespace && ((Namespace) ctx).IsInline;
if (string.IsNullOrWhiteSpace(ctx.Name) || isInlineNamespace)
return;
if (ContextKind != TypePrinterContextKind.Managed)
{
names.Push(ctx.Name);
return;
}
string name = null;
var @class = ctx as Class;
if (@class != null)
{
if (@class.IsTemplate)
name = $@"{ctx.Name}<{string.Join(", ",
@class.TemplateParameters.Select(p => p.Name))}>";
else
{
var specialization = @class as ClassTemplateSpecialization;
if (specialization != null)
{
name = $@"{ctx.Name}<{string.Join(", ",
specialization.Arguments.Select(VisitTemplateArgument))}>";
}
}
}
names.Push(name ?? ctx.Name);
}
private CSharpExpressionPrinter expressionPrinter => new CSharpExpressionPrinter(this); private CSharpExpressionPrinter expressionPrinter => new CSharpExpressionPrinter(this);
} }
} }

2
src/Generator/Passes/CheckIgnoredDecls.cs

@ -36,7 +36,7 @@ namespace CppSharp.Passes
if (@class.IsInjected) if (@class.IsInjected)
injectedClasses.Add(@class); injectedClasses.Add(@class);
if (!@class.IsDependent) if (!@class.IsTemplate)
return true; return true;
if (Options.GenerateClassTemplates) if (Options.GenerateClassTemplates)

2
src/Generator/Passes/TrimSpecializationsPass.cs

@ -37,7 +37,7 @@ namespace CppSharp.Passes
if (!base.VisitClassDecl(@class)) if (!base.VisitClassDecl(@class))
return false; return false;
if (@class.IsDependent) if (@class.IsTemplate)
{ {
templates.Add(@class); templates.Add(@class);
foreach (var specialization in @class.Specializations.Where( foreach (var specialization in @class.Specializations.Where(

1
tests/CSharp/CSharp.cs

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using CppSharp.AST; using CppSharp.AST;

8
tests/CSharp/CSharpTemplates.h

@ -136,6 +136,7 @@ public:
DependentValueFields operator+(const DependentValueFields& other); DependentValueFields operator+(const DependentValueFields& other);
T getDependentValue(); T getDependentValue();
void setDependentValue(const T& value); void setDependentValue(const T& value);
IndependentFields<Nested> returnNestedInTemplate();
private: private:
T field{}; T field{};
union { union {
@ -165,6 +166,12 @@ void DependentValueFields<T>::setDependentValue(const T& value)
field = value; field = value;
} }
template <typename T>
IndependentFields<typename DependentValueFields<T>::Nested> DependentValueFields<T>::returnNestedInTemplate()
{
return DependentValueFields<T>::Nested();
}
template <typename T> template <typename T>
DependentValueFields<T>& DependentValueFields<T>::returnInjectedClass() DependentValueFields<T>& DependentValueFields<T>::returnInjectedClass()
{ {
@ -532,6 +539,7 @@ template class DLL_API IndependentFields<T1>;
template class DLL_API IndependentFields<std::string>; template class DLL_API IndependentFields<std::string>;
template class DLL_API Base<int>; template class DLL_API Base<int>;
template class DLL_API DependentValueFields<int>; template class DLL_API DependentValueFields<int>;
template DLL_API IndependentFields<DependentValueFields<int>::Nested> DependentValueFields<int>::returnNestedInTemplate();
template class DLL_API VirtualTemplate<int>; template class DLL_API VirtualTemplate<int>;
template class DLL_API VirtualTemplate<bool>; template class DLL_API VirtualTemplate<bool>;
template class DLL_API HasDefaultTemplateArgument<int, int>; template class DLL_API HasDefaultTemplateArgument<int, int>;

Loading…
Cancel
Save