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

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

@ -271,7 +271,16 @@ namespace CppSharp.Generators.CSharp @@ -271,7 +271,16 @@ namespace CppSharp.Generators.CSharp
GenerateClassInternals(specialization);
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);
WriteCloseBraceIndent();
@ -329,7 +338,7 @@ namespace CppSharp.Generators.CSharp @@ -329,7 +338,7 @@ namespace CppSharp.Generators.CSharp
foreach (var nestedTemplate in @class.Classes.Where(c => !c.IsIncomplete && c.IsDependent))
GenerateClassTemplateSpecializationInternal(nestedTemplate);
if (@class.IsDependent)
if (@class.IsTemplate)
{
if (!(@class.Namespace is Class))
GenerateClassTemplateSpecializationInternal(@class);

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

@ -570,7 +570,7 @@ namespace CppSharp.Generators.CSharp @@ -570,7 +570,7 @@ namespace CppSharp.Generators.CSharp
Helpers.InternalStruct}{Helpers.GetSuffixForInternal(@class)}";
var printed = VisitDeclaration(@class).Type;
if (!@class.IsDependent)
if (!@class.IsTemplate)
return printed;
return $@"{printed}<{string.Join(", ",
@class.TemplateParameters.Select(p => p.Name))}>";
@ -638,9 +638,7 @@ namespace CppSharp.Generators.CSharp @@ -638,9 +638,7 @@ namespace CppSharp.Generators.CSharp
while (!(ctx is TranslationUnit))
{
var isInlineNamespace = ctx is Namespace && ((Namespace)ctx).IsInline;
if (!string.IsNullOrWhiteSpace(ctx.Name) && !isInlineNamespace)
names.Push(ctx.Name);
AddContextName(names, ctx);
ctx = ctx.Namespace;
}
@ -802,6 +800,38 @@ namespace CppSharp.Generators.CSharp @@ -802,6 +800,38 @@ namespace CppSharp.Generators.CSharp
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);
}
}

2
src/Generator/Passes/CheckIgnoredDecls.cs

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

2
src/Generator/Passes/TrimSpecializationsPass.cs

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

1
tests/CSharp/CSharp.cs

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

8
tests/CSharp/CSharpTemplates.h

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

Loading…
Cancel
Save