Skip to content

Commit f599d4d

Browse files
Merge pull request #384 from tannergooding/main
Few misc fixups to better handle some C++ patterns
2 parents bafcf0d + e309ab1 commit f599d4d

File tree

9 files changed

+315
-54
lines changed

9 files changed

+315
-54
lines changed

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -673,11 +673,19 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
673673
outputBuilder.Write("return ");
674674
}
675675

676-
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == cxxMethodDecl.Parent).Single();
677-
var baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
678-
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
676+
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == cxxMethodDecl.Parent).SingleOrDefault();
679677

680-
outputBuilder.Write(baseFieldName);
678+
if (cxxBaseSpecifier != null)
679+
{
680+
var baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
681+
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
682+
outputBuilder.Write(baseFieldName);
683+
}
684+
else
685+
{
686+
outputBuilder.Write("Base");
687+
}
688+
681689
outputBuilder.Write('.');
682690
outputBuilder.Write(name);
683691
outputBuilder.Write('(');
@@ -3504,7 +3512,12 @@ private bool IsConstant(string targetTypeName, Expr initExpr)
35043512

35053513
// case CX_StmtClass.CX_StmtClass_CXXTemporaryObjectExpr:
35063514
// case CX_StmtClass.CX_StmtClass_CXXDefaultArgExpr:
3507-
// case CX_StmtClass.CX_StmtClass_CXXDefaultInitExpr:
3515+
3516+
case CX_StmtClass.CX_StmtClass_CXXDefaultInitExpr:
3517+
{
3518+
return false;
3519+
}
3520+
35083521
// case CX_StmtClass.CX_StmtClass_CXXDeleteExpr:
35093522

35103523
case CX_StmtClass.CX_StmtClass_CXXDependentScopeMemberExpr:
@@ -3669,7 +3682,11 @@ private bool IsConstant(string targetTypeName, Expr initExpr)
36693682
return true;
36703683
}
36713684

3672-
// case CX_StmtClass.CX_StmtClass_LambdaExpr:
3685+
case CX_StmtClass.CX_StmtClass_LambdaExpr:
3686+
{
3687+
return false;
3688+
}
3689+
36733690
// case CX_StmtClass.CX_StmtClass_MSPropertyRefExpr:
36743691
// case CX_StmtClass.CX_StmtClass_MSPropertySubscriptExpr:
36753692
// case CX_StmtClass.CX_StmtClass_MaterializeTemporaryExpr:
@@ -3741,7 +3758,11 @@ private bool IsConstant(string targetTypeName, Expr initExpr)
37413758
return true;
37423759
}
37433760

3744-
// case CX_StmtClass.CX_StmtClass_SubstNonTypeTemplateParmExpr:
3761+
case CX_StmtClass.CX_StmtClass_SubstNonTypeTemplateParmExpr:
3762+
{
3763+
return false;
3764+
}
3765+
37453766
// case CX_StmtClass.CX_StmtClass_SubstNonTypeTemplateParmPackExpr:
37463767
// case CX_StmtClass.CX_StmtClass_TypeTraitExpr:
37473768
// case CX_StmtClass.CX_StmtClass_TypoExpr:

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs

Lines changed: 170 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ private void VisitCallExpr(CallExpr callExpr)
115115
}
116116
}
117117

118+
var isUnusedValue = false;
119+
120+
if (callExpr.Type.CanonicalType.Kind != CXTypeKind.CXType_Void)
121+
{
122+
isUnusedValue = IsPrevContextStmt<CompoundStmt>(out _, out _)
123+
|| IsPrevContextStmt<IfStmt>(out _, out _);
124+
125+
if ((calleeDecl is FunctionDecl functionDecl) && (functionDecl.Name is "memcpy" or "memset"))
126+
{
127+
isUnusedValue = false;
128+
}
129+
}
130+
131+
if (isUnusedValue)
132+
{
133+
outputBuilder.Write("_ = ");
134+
}
135+
118136
if (calleeDecl is null)
119137
{
120138
Visit(callExpr.Callee);
@@ -139,22 +157,64 @@ private void VisitCallExpr(CallExpr callExpr)
139157

140158
case "memset":
141159
{
160+
NamedDecl namedDecl = null;
161+
162+
if (callExpr.NumArgs == 3)
163+
{
164+
if (IsStmtAsWritten<IntegerLiteral>(callExpr.Args[1], out var integerLiteralExpr, removeParens: true) && (integerLiteralExpr.Value == 0) &&
165+
IsStmtAsWritten<UnaryExprOrTypeTraitExpr>(callExpr.Args[2], out var unaryExprOrTypeTraitExpr, removeParens: true) && (unaryExprOrTypeTraitExpr.Kind == CX_UnaryExprOrTypeTrait.CX_UETT_SizeOf))
166+
{
167+
var typeOfArgument = unaryExprOrTypeTraitExpr.TypeOfArgument.CanonicalType;
168+
var expr = callExpr.Args[0];
169+
170+
if (IsStmtAsWritten<UnaryOperator>(expr, out var unaryOperator, removeParens: true) && (unaryOperator.Opcode == CX_UnaryOperatorKind.CX_UO_AddrOf))
171+
{
172+
expr = unaryOperator.SubExpr;
173+
}
174+
175+
if (IsStmtAsWritten<DeclRefExpr>(expr, out var declRefExpr, removeParens: true) && (typeOfArgument == declRefExpr.Type.CanonicalType))
176+
{
177+
namedDecl = declRefExpr.Decl;
178+
}
179+
else if (IsStmtAsWritten<MemberExpr>(expr, out var memberExpr, removeParens: true) && (typeOfArgument == memberExpr.Type.CanonicalType))
180+
{
181+
namedDecl = memberExpr.MemberDecl;
182+
}
183+
}
184+
185+
if (namedDecl is not null)
186+
{
187+
outputBuilder.Write(GetRemappedCursorName(namedDecl));
188+
outputBuilder.Write(" = default");
189+
break;
190+
}
191+
}
192+
142193
outputBuilder.AddUsingDirective("System.Runtime.CompilerServices");
143194
outputBuilder.Write("Unsafe.InitBlockUnaligned");
144195
VisitArgs(callExpr);
145196
break;
146197
}
147198

148-
default:
199+
case "wcslen":
149200
{
150-
if ((functionDecl.ReturnType.CanonicalType.Kind != CXTypeKind.CXType_Void) && IsPrevContextStmt<CompoundStmt>(out _, out _))
201+
if (_config.GenerateCompatibleCode)
151202
{
152-
outputBuilder.Write("_ = ");
203+
goto default;
153204
}
154205

155-
Visit(callExpr.Callee);
206+
outputBuilder.AddUsingDirective("System.Runtime.InteropServices");
207+
outputBuilder.Write("MemoryMarshal.CreateReadOnlySpanFromNullTerminated");
208+
156209
VisitArgs(callExpr);
210+
outputBuilder.Write(".Length");
211+
break;
212+
}
157213

214+
default:
215+
{
216+
Visit(callExpr.Callee);
217+
VisitArgs(callExpr);
158218
break;
159219
}
160220
}
@@ -176,19 +236,53 @@ private void VisitCallExpr(CallExpr callExpr)
176236

177237
void VisitArgs(CallExpr callExpr)
178238
{
239+
var callExprType = (callExpr.Callee is MemberExpr memberExpr)
240+
? memberExpr.MemberDecl.Type.CanonicalType
241+
: callExpr.Callee.Type.CanonicalType;
242+
243+
if (callExprType is PointerType pointerType)
244+
{
245+
callExprType = pointerType.PointeeType.CanonicalType;
246+
}
247+
179248
outputBuilder.Write('(');
180249

181250
var args = callExpr.Args;
182251
var needsComma = false;
183252

184253
for (var i = 0; i < args.Count; i++)
185254
{
186-
if (needsComma)
255+
var arg = args[i];
256+
257+
if (needsComma && (arg is not CXXDefaultArgExpr))
187258
{
188259
outputBuilder.Write(", ");
189260
}
190261

191-
var arg = args[i];
262+
if (callExprType is FunctionProtoType functionProtoType)
263+
{
264+
var paramType = functionProtoType.ParamTypes[i].CanonicalType;
265+
266+
if (paramType is ReferenceType)
267+
{
268+
if (IsStmtAsWritten<UnaryOperator>(arg, out var unaryOperator, removeParens: true) && (unaryOperator.Opcode == CX_UnaryOperatorKind.CX_UO_Deref))
269+
{
270+
arg = unaryOperator.SubExpr;
271+
}
272+
else if (IsStmtAsWritten<DeclRefExpr>(arg, out var declRefExpr, removeParens: true))
273+
{
274+
if (declRefExpr.Decl.Type.CanonicalType is not ReferenceType and not PointerType)
275+
{
276+
outputBuilder.Write('&');
277+
}
278+
}
279+
else if (arg.Type.CanonicalType is not ReferenceType and not PointerType)
280+
{
281+
outputBuilder.Write('&');
282+
}
283+
}
284+
}
285+
192286
Visit(arg);
193287

194288
if (arg is not CXXDefaultArgExpr)
@@ -651,14 +745,14 @@ private void VisitDeclRefExpr(DeclRefExpr declRefExpr)
651745
{
652746
var className = GetClass(enumName);
653747

654-
if (outputBuilder.Name != className)
748+
if ((outputBuilder.Name != className) && (namedDecl.Parent is not TagDecl))
655749
{
656-
outputBuilder.AddUsingDirective($"static {GetNamespace(enumName)}.{className}");
750+
outputBuilder.AddUsingDirective($"static {GetNamespace(enumName, namedDecl)}.{className}");
657751
}
658752
}
659753
else
660754
{
661-
outputBuilder.AddUsingDirective($"static {GetNamespace(enumName)}.{enumName}");
755+
outputBuilder.AddUsingDirective($"static {GetNamespace(enumName, namedDecl)}.{enumName}");
662756
}
663757
}
664758
else
@@ -1003,12 +1097,33 @@ void ForEnumConstantDecl(ImplicitCastExpr implicitCastExpr, EnumConstantDecl enu
10031097
if (IsPrevContextStmt<BinaryOperator>(out var binaryOperator, out _) && ((binaryOperator.Opcode == CX_BinaryOperatorKind.CX_BO_EQ) || (binaryOperator.Opcode == CX_BinaryOperatorKind.CX_BO_NE)))
10041098
{
10051099
Visit(subExpr);
1100+
subExpr = null;
1101+
}
1102+
else if (IsPrevContextStmt<CaseStmt>(out _, out _))
1103+
{
1104+
var previousContext = _context.Last.Previous;
1105+
1106+
do
1107+
{
1108+
previousContext = previousContext.Previous;
1109+
}
1110+
while (previousContext.Value.Cursor is ParenExpr or ImplicitCastExpr or CaseStmt or CompoundStmt);
1111+
1112+
var value = previousContext.Value;
1113+
1114+
if ((value.Cursor is SwitchStmt switchStmt) && (switchStmt.Cond.IgnoreImplicit.Type.CanonicalType is EnumType))
1115+
{
1116+
Visit(subExpr);
1117+
subExpr = null;
1118+
}
10061119
}
10071120
else if (IsPrevContextDecl<EnumConstantDecl>(out _, out _))
10081121
{
10091122
Visit(subExpr);
1123+
subExpr = null;
10101124
}
1011-
else
1125+
1126+
if (subExpr is not null)
10121127
{
10131128
var type = implicitCastExpr.Type;
10141129

@@ -1272,7 +1387,7 @@ void ForType(InitListExpr initListExpr, Type type)
12721387
}
12731388
else
12741389
{
1275-
AddDiagnostic(DiagnosticLevel.Error, $"Unsupported init list expression type: '{type.KindSpelling}'. Generated bindings may be incomplete.", initListExpr);
1390+
AddDiagnostic(DiagnosticLevel.Error, $"Unsupported init list expression type: '{type.TypeClassSpelling}'. Generated bindings may be incomplete.", initListExpr);
12761391
}
12771392
}
12781393

@@ -1335,6 +1450,14 @@ void HandleInitStmt(Stmt init)
13351450
break;
13361451
}
13371452

1453+
case CXEvalResultKind.CXEval_StrLiteral:
1454+
{
1455+
outputBuilder.Write('"');
1456+
outputBuilder.Write(evaluation.AsStr);
1457+
outputBuilder.Write('"');
1458+
break;
1459+
}
1460+
13381461
default:
13391462
{
13401463
AddDiagnostic(DiagnosticLevel.Error, $"Unsupported evaluation kind: '{evaluation.Kind}'. Generated bindings may be incomplete.", init);
@@ -1605,18 +1728,26 @@ private void VisitMemberExpr(MemberExpr memberExpr)
16051728
{
16061729
if ((_cxxRecordDeclContext is not null) && (_cxxRecordDeclContext != cxxMethodDecl.Parent) && HasField(cxxMethodDecl.Parent))
16071730
{
1608-
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == cxxMethodDecl.Parent).Single();
1609-
baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
1610-
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
1731+
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == cxxMethodDecl.Parent).SingleOrDefault();
1732+
1733+
if (cxxBaseSpecifier is not null)
1734+
{
1735+
baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
1736+
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
1737+
}
16111738
}
16121739
}
16131740
else if (memberExpr.MemberDecl is FieldDecl fieldDecl)
16141741
{
16151742
if ((_cxxRecordDeclContext is not null) && (_cxxRecordDeclContext != fieldDecl.Parent))
16161743
{
1617-
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == fieldDecl.Parent).Single();
1618-
baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
1619-
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
1744+
var cxxBaseSpecifier = _cxxRecordDeclContext.Bases.Where((baseSpecifier) => baseSpecifier.Referenced == fieldDecl.Parent).SingleOrDefault();
1745+
1746+
if (cxxBaseSpecifier is not null)
1747+
{
1748+
baseFieldName = GetAnonymousName(cxxBaseSpecifier, "Base");
1749+
baseFieldName = GetRemappedName(baseFieldName, cxxBaseSpecifier, tryRemapOperatorName: true, out var wasRemapped, skipUsing: true);
1750+
}
16201751
}
16211752
}
16221753
}
@@ -1710,6 +1841,15 @@ private void VisitReturnStmt(ReturnStmt returnStmt)
17101841
if (returnStmt.RetValue != null)
17111842
{
17121843
outputBuilder.Write(' ');
1844+
1845+
if (functionDecl.ReturnType.CanonicalType is not ReferenceType and not PointerType)
1846+
{
1847+
if (returnStmt.RetValue.Type.CanonicalType is ReferenceType)
1848+
{
1849+
outputBuilder.Write('*');
1850+
}
1851+
}
1852+
17131853
Visit(returnStmt.RetValue);
17141854
}
17151855
}
@@ -2609,8 +2749,21 @@ private void VisitUnaryOperator(UnaryOperator unaryOperator)
26092749
}
26102750
else if (canonicalType is PointerType or ReferenceType)
26112751
{
2752+
var needsParens = !IsPrevContextStmt<ParenExpr>(out _, out _, preserveParen: true) &&
2753+
!IsPrevContextStmt<IfStmt>(out _, out _, preserveParen: true);
2754+
2755+
if (needsParens)
2756+
{
2757+
outputBuilder.Write('(');
2758+
}
2759+
26122760
Visit(subExpr);
26132761
outputBuilder.Write(" == null");
2762+
2763+
if (needsParens)
2764+
{
2765+
outputBuilder.Write(')');
2766+
}
26142767
}
26152768
else
26162769
{

0 commit comments

Comments
 (0)