Skip to content

Commit a491350

Browse files
ddobrevtritao
authored andcommitted
Added type maps for primitive strings (pointers to char).
const char*, const char16_t* and const wchar_t* in particular. This enables comparison of types when resolving ambiguity. Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent e203463 commit a491350

File tree

9 files changed

+212
-146
lines changed

9 files changed

+212
-146
lines changed

src/AST/CppTypePrinter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public virtual string VisitTypedefType(TypedefType typedef, TypeQualifiers quals
181181
{
182182
FunctionType func;
183183
if (ResolveTypedefs && !typedef.Declaration.Type.IsPointerTo(out func))
184-
return typedef.Declaration.Type.Visit(this);
184+
return typedef.Declaration.Type.Visit(this, quals);
185185
var qual = GetStringQuals(quals);
186186
return $"{qual}{typedef.Declaration.Visit(this)}";
187187
}

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 42 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public CSharpMarshalNativeToManagedPrinter(CSharpMarshalContext context)
4646
typePrinter = new CSharpTypePrinter(context.Context);
4747
}
4848

49-
public bool MarshalsParameter { get; set; }
50-
5149
public override bool VisitType(Type type, TypeQualifiers quals)
5250
{
5351
TypeMap typeMap;
@@ -132,10 +130,11 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
132130
// const char* and const char[] are the same so we can use a string
133131
if (array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) &&
134132
array.QualifiedType.Qualifiers.IsConst)
135-
return VisitPointerType(new PointerType
136-
{
137-
QualifiedPointee = array.QualifiedType
138-
}, quals);
133+
{
134+
var pointer = new PointerType { QualifiedPointee = array.QualifiedType };
135+
Context.ReturnType = new QualifiedType(pointer);
136+
return this.VisitPointerType(pointer, quals);
137+
}
139138
MarshalArray(array);
140139
break;
141140
case ArrayType.ArraySize.Variable:
@@ -155,79 +154,45 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
155154
var isRefParam = param != null && (param.IsInOut || param.IsOut);
156155

157156
var pointee = pointer.Pointee.Desugar();
158-
bool marshalPointeeAsString = pointee.IsConstCharString() && isRefParam;
157+
var finalPointee = pointer.GetFinalPointee().Desugar();
158+
PrimitiveType primitive;
159+
if ((pointee.IsConstCharString() && isRefParam) ||
160+
(!finalPointee.IsPrimitiveType(out primitive) &&
161+
!finalPointee.IsEnumType()))
162+
return pointer.QualifiedPointee.Visit(this);
159163

160-
if ((pointer.IsConstCharString() && !MarshalsParameter) ||
161-
marshalPointeeAsString)
164+
if (isRefParam)
162165
{
163-
Context.Return.Write(MarshalStringToManaged(Context.ReturnVarName,
164-
pointer.GetFinalPointee().Desugar() as BuiltinType));
166+
Context.Return.Write("_{0}", param.Name);
165167
return true;
166168
}
167169

168-
var finalPointee = pointer.GetFinalPointee();
169-
PrimitiveType primitive;
170-
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
170+
if (Context.Context.Options.MarshalCharAsManagedChar &&
171+
primitive == PrimitiveType.Char)
172+
Context.Return.Write($"({pointer}) ");
173+
174+
var type = Context.ReturnType.Type.Desugar(
175+
resolveTemplateSubstitution: false);
176+
if (Context.Function != null &&
177+
Context.Function.OperatorKind == CXXOperatorKind.Subscript)
171178
{
172-
if (isRefParam)
179+
if (type.IsPrimitiveType(primitive))
173180
{
174-
Context.Return.Write("_{0}", param.Name);
175-
return true;
181+
Context.Return.Write("*");
176182
}
177-
178-
if (Context.Context.Options.MarshalCharAsManagedChar &&
179-
primitive == PrimitiveType.Char)
180-
Context.Return.Write($"({pointer}) ");
181-
182-
var type = Context.ReturnType.Type.Desugar(
183-
resolveTemplateSubstitution: false);
184-
if (Context.Function != null &&
185-
Context.Function.OperatorKind == CXXOperatorKind.Subscript)
183+
else
186184
{
187-
if (type.IsPrimitiveType(primitive))
188-
{
189-
Context.Return.Write("*");
190-
}
191-
else
192-
{
193-
var templateParameter = type as TemplateParameterType;
194-
if (templateParameter != null)
195-
Context.Return.Write($"({templateParameter.Parameter.Name}) (object) *");
196-
}
185+
var templateParameter = type as TemplateParameterType;
186+
if (templateParameter != null)
187+
Context.Return.Write($"({templateParameter.Parameter.Name}) (object) *");
197188
}
198-
199-
if (new QualifiedType(pointer, quals).IsConstRefToPrimitive())
200-
Context.Return.Write("*");
201-
202-
Context.Return.Write(Context.ReturnVarName);
203-
return true;
204189
}
205190

206-
return pointer.QualifiedPointee.Visit(this);
207-
}
191+
if (new QualifiedType(pointer, quals).IsConstRefToPrimitive())
192+
Context.Return.Write("*");
208193

209-
private string MarshalStringToManaged(string varName, BuiltinType type)
210-
{
211-
var isChar = type.Type == PrimitiveType.Char;
212-
var encoding = isChar ? Encoding.ASCII : Encoding.Unicode;
213-
214-
if (Equals(encoding, Encoding.ASCII))
215-
encoding = Context.Context.Options.Encoding;
216-
217-
if (Equals(encoding, Encoding.ASCII))
218-
return $"Marshal.PtrToStringAnsi({varName})";
219-
220-
if (Equals(encoding, Encoding.UTF8))
221-
return $"Marshal.PtrToStringUTF8({varName})";
222-
223-
// If we reach this, we know the string is Unicode.
224-
if (type.Type == PrimitiveType.Char ||
225-
Context.Context.TargetInfo.WCharWidth == 16)
226-
return $"Marshal.PtrToStringUni({varName})";
227-
228-
// If we reach this, we should have an UTF-32 wide string.
229-
const string encodingName = "System.Text.Encoding.UTF32";
230-
return $"CppSharp.Runtime.Helpers.MarshalEncodedString({varName}, {encodingName})";
194+
Context.Return.Write(Context.ReturnVarName);
195+
return true;
231196
}
232197

233198
public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
@@ -377,11 +342,11 @@ private string HandleReturnedPointer(Class @class, string qualifiedClass)
377342
if (dtor != null && dtor.IsVirtual)
378343
{
379344
Context.Before.WriteLine("else {0}{1} = ({2}) {3}.{4}({5}{6});",
380-
MarshalsParameter
345+
Context.Parameter != null
381346
? string.Empty
382347
: string.Format("{0}.NativeToManagedMap[{1}] = ", qualifiedClass, Context.ReturnVarName),
383348
ret, qualifiedIdentifier, qualifiedClass, Helpers.CreateInstanceIdentifier, Context.ReturnVarName,
384-
MarshalsParameter ? ", skipVTables: true" : string.Empty);
349+
Context.Parameter != null ? ", skipVTables: true" : string.Empty);
385350
}
386351
else
387352
{
@@ -554,7 +519,6 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
554519
if (templateSubstitution != null)
555520
realPointer = templateSubstitution.Replacement.Type.Desugar() as PointerType;
556521
realPointer = realPointer ?? pointer;
557-
var pointee = pointer.Pointee.Desugar();
558522
if (Context.Function != null &&
559523
(realPointer.IsPrimitiveTypeConvertibleToRef() ||
560524
(templateSubstitution != null && realPointer.Pointee.IsEnumType())) &&
@@ -597,23 +561,20 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
597561
var param = Context.Parameter;
598562
var isRefParam = param != null && (param.IsInOut || param.IsOut);
599563

564+
var pointee = pointer.Pointee.Desugar();
600565
if (pointee.IsConstCharString() && isRefParam)
601566
{
602567
if (param.IsOut)
603568
{
604569
Context.Return.Write("IntPtr.Zero");
605570
Context.ArgumentPrefix.Write("&");
571+
return true;
606572
}
607-
else if (param.IsInOut)
608-
{
609-
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
573+
pointer.QualifiedPointee.Visit(this);
574+
if (param.IsInOut)
610575
Context.ArgumentPrefix.Write("&");
611-
}
612576
else
613-
{
614-
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
615577
Context.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName);
616-
}
617578
return true;
618579
}
619580

@@ -643,11 +604,9 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
643604
return true;
644605
}
645606

646-
var marshalAsString = pointer.IsConstCharString();
647607
var finalPointee = pointer.GetFinalPointee();
648608
PrimitiveType primitive;
649-
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType() ||
650-
marshalAsString)
609+
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
651610
{
652611
// From MSDN: "note that a ref or out parameter is classified as a moveable
653612
// variable". This means we must create a local variable to hold the result
@@ -670,23 +629,13 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
670629
}
671630
else
672631
{
673-
if (!marshalAsString &&
674-
Context.Context.Options.MarshalCharAsManagedChar &&
632+
if (Context.Context.Options.MarshalCharAsManagedChar &&
675633
primitive == PrimitiveType.Char)
676634
Context.Return.Write($"({typePrinter.PrintNative(pointer)}) ");
677635

678-
if (marshalAsString && (Context.MarshalKind == MarshalKind.NativeField ||
679-
Context.MarshalKind == MarshalKind.VTableReturnValue ||
680-
Context.MarshalKind == MarshalKind.Variable))
681-
{
682-
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
683-
}
684-
else
685-
{
686-
if (qualifiedPointer.IsConstRefToPrimitive())
687-
Context.Return.Write("&");
688-
Context.Return.Write(Context.Parameter.Name);
689-
}
636+
if (qualifiedPointer.IsConstRefToPrimitive())
637+
Context.Return.Write("&");
638+
Context.Return.Write(Context.Parameter.Name);
690639
}
691640

692641
return true;
@@ -695,21 +644,6 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
695644
return pointer.QualifiedPointee.Visit(this);
696645
}
697646

698-
private string MarshalStringToUnmanaged(string varName)
699-
{
700-
if (Equals(Context.Context.Options.Encoding, Encoding.ASCII))
701-
{
702-
return string.Format("Marshal.StringToHGlobalAnsi({0})", varName);
703-
}
704-
if (Equals(Context.Context.Options.Encoding, Encoding.Unicode) ||
705-
Equals(Context.Context.Options.Encoding, Encoding.BigEndianUnicode))
706-
{
707-
return string.Format("Marshal.StringToHGlobalUni({0})", varName);
708-
}
709-
throw new NotSupportedException(string.Format("{0} is not supported yet.",
710-
Context.Context.Options.Encoding.EncodingName));
711-
}
712-
713647
public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
714648
{
715649
switch (primitive)

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -927,12 +927,12 @@ private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldT
927927
if (type.IsPointer())
928928
{
929929
Type pointee = type.GetFinalPointee();
930-
if (pointee.IsPrimitiveType() && !type.IsConstCharString())
930+
if (pointee.IsPrimitiveType())
931931
{
932932
Write($"({CSharpTypePrinter.IntPtrType}) ");
933933
var templateSubstitution = pointee.Desugar(false) as TemplateParameterSubstitutionType;
934934
if (templateSubstitution != null)
935-
Write($"(object) ");
935+
Write("(object) ");
936936
}
937937
}
938938
WriteLine($"{marshal.Context.Return};");
@@ -1672,11 +1672,12 @@ private void GenerateVTableManagedCall(Method method)
16721672
{
16731673
ReturnType = param.QualifiedType,
16741674
ReturnVarName = param.Name,
1675-
ParameterIndex = i
1675+
ParameterIndex = i,
1676+
Parameter = param
16761677
};
16771678

16781679
ctx.PushMarshalKind(MarshalKind.GenericDelegate);
1679-
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx) { MarshalsParameter = true };
1680+
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx);
16801681
param.Visit(marshal);
16811682
ctx.PopMarshalKind();
16821683

src/Generator/Generators/CSharp/CSharpTypePrinter.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,16 +184,16 @@ public override TypePrinterResult VisitPointerType(PointerType pointer,
184184

185185
if (allowStrings && pointer.IsConstCharString())
186186
{
187-
if (isManagedContext)
188-
return "string";
189-
if (Parameter == null || Parameter.Name == Helpers.ReturnIdentifier)
190-
return IntPtrType;
191-
if (Options.Encoding == Encoding.ASCII)
192-
return string.Format("[MarshalAs(UnmanagedType.LPStr)] string");
193-
if (Options.Encoding == Encoding.Unicode ||
194-
Options.Encoding == Encoding.BigEndianUnicode)
195-
return string.Format("[MarshalAs(UnmanagedType.LPWStr)] string");
196-
throw new NotSupportedException($"{Options.Encoding.EncodingName} is not supported yet.");
187+
TypeMap typeMap;
188+
TypeMapDatabase.FindTypeMap(pointer, out typeMap);
189+
var typePrinterContext = new TypePrinterContext()
190+
{
191+
Kind = Kind,
192+
MarshalKind = MarshalKind,
193+
Type = pointer.Pointee,
194+
Parameter = Parameter
195+
};
196+
return typeMap.CSharpSignatureType(typePrinterContext).Visit(this);
197197
}
198198

199199
var pointee = pointer.Pointee.Desugar();

0 commit comments

Comments
 (0)