Skip to content

Commit 86ef17c

Browse files
authored
Merge pull request #118 from sselecirPyM/main
Add a BodySpan property to the CppFunction class.
2 parents b9efb2d + ac21093 commit 86ef17c

File tree

5 files changed

+476
-4
lines changed

5 files changed

+476
-4
lines changed

src/CppAst.Tests/TestFunctions.cs

Lines changed: 353 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using NUnit.Framework;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
25

36
namespace CppAst.Tests
47
{
@@ -224,7 +227,7 @@ public void TestFunctionExport()
224227
Assert.True(cppFunction.IsPublicExport());
225228
}
226229
},
227-
new CppParserOptions() { }
230+
new CppParserOptions() { }
228231
);
229232

230233
ParseAssert(text,
@@ -353,7 +356,356 @@ public void TestFunctionPointersByParam()
353356
);
354357
}
355358

359+
[Test]
360+
public void TestFunctionBody()
361+
{
362+
var options = new CppParserOptions();
363+
options.ParseFunctionBodies = true;
364+
var headerFilename = "test_function_body.h";
365+
366+
var text = @"
367+
void function0();
368+
int function1(int a, float b) {
369+
return a + (int)b;
370+
}
371+
float function2(int x);
372+
";
373+
374+
var currentDirectory = Environment.CurrentDirectory;
375+
var headerFile = Path.Combine(currentDirectory, headerFilename);
376+
File.WriteAllText(headerFile, text);
377+
378+
var compilation = CppParser.ParseFile(headerFile, options);
379+
380+
Assert.False(compilation.HasErrors);
381+
Assert.AreEqual(3, compilation.Functions.Count);
382+
383+
{
384+
var cppFunction = compilation.Functions[0];
385+
Assert.AreEqual("function0", cppFunction.Name);
386+
Assert.IsNull(cppFunction.BodySpan);
387+
}
388+
389+
{
390+
var cppFunction = compilation.Functions[1];
391+
Assert.AreEqual("function1", cppFunction.Name);
392+
Assert.IsNotNull(cppFunction.BodySpan);
393+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
394+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
395+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
396+
}
397+
398+
{
399+
var cppFunction = compilation.Functions[2];
400+
Assert.AreEqual("function2", cppFunction.Name);
401+
Assert.IsNull(cppFunction.BodySpan);
402+
}
403+
}
404+
405+
[Test]
406+
public void TestInlineMethodBody()
407+
{
408+
var options = new CppParserOptions();
409+
options.ParseFunctionBodies = true;
410+
var headerFilename = "test_inline_method_body.h";
411+
412+
var text = @"
413+
typedef unsigned int ImWchar;
414+
415+
class ImFont {
416+
public:
417+
bool IsGlyphInFont(ImWchar c)
418+
{
419+
return false;
420+
}
421+
422+
bool AnotherMethod(ImWchar c) {
423+
if (c == 0) return true;
424+
return false;
425+
}
426+
};
427+
";
428+
429+
var currentDirectory = Environment.CurrentDirectory;
430+
var headerFile = Path.Combine(currentDirectory, headerFilename);
431+
File.WriteAllText(headerFile, text);
432+
433+
var compilation = CppParser.ParseFile(headerFile, options);
434+
435+
Assert.False(compilation.HasErrors);
436+
Assert.AreEqual(1, compilation.Classes.Count);
437+
438+
var cls = compilation.Classes[0];
439+
Assert.AreEqual("ImFont", cls.Name);
440+
Assert.AreEqual(2, cls.Functions.Count);
441+
442+
{
443+
var cppFunction = cls.Functions[0];
444+
Assert.AreEqual("IsGlyphInFont", cppFunction.Name);
445+
Assert.IsNotNull(cppFunction.BodySpan, "IsGlyphInFont should have BodySpan - this is the bug reported");
446+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
447+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
448+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
449+
}
450+
451+
{
452+
var cppFunction = cls.Functions[1];
453+
Assert.AreEqual("AnotherMethod", cppFunction.Name);
454+
Assert.IsNotNull(cppFunction.BodySpan, "AnotherMethod should have BodySpan");
455+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
456+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
457+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
458+
}
459+
}
460+
461+
[Test]
462+
public void TestFunctionOverloadBodySpan()
463+
{
464+
var options = new CppParserOptions();
465+
options.ParseFunctionBodies = true;
466+
var headerFilename = "test_function_overload_body.h";
467+
468+
var text = @"
469+
int process(int x)
470+
{
471+
return x * 2;
472+
}
356473
474+
int process(float y)
475+
{
476+
return (int)(y * 3.0f);
477+
}
478+
479+
int process(int x, int y)
480+
{
481+
return x + y;
482+
}
483+
";
484+
485+
var currentDirectory = Environment.CurrentDirectory;
486+
var headerFile = Path.Combine(currentDirectory, headerFilename);
487+
File.WriteAllText(headerFile, text);
488+
489+
var compilation = CppParser.ParseFile(headerFile, options);
490+
491+
Assert.False(compilation.HasErrors);
492+
Assert.AreEqual(3, compilation.Functions.Count);
493+
494+
{
495+
var cppFunction = compilation.Functions[0];
496+
Assert.AreEqual("process", cppFunction.Name);
497+
Assert.AreEqual(1, cppFunction.Parameters.Count);
498+
Assert.IsNotNull(cppFunction.BodySpan, "process(int) should have BodySpan");
499+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
500+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
501+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
502+
}
503+
504+
{
505+
var cppFunction = compilation.Functions[1];
506+
Assert.AreEqual("process", cppFunction.Name);
507+
Assert.AreEqual(1, cppFunction.Parameters.Count);
508+
Assert.IsNotNull(cppFunction.BodySpan, "process(float) should have BodySpan");
509+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
510+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
511+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
512+
}
513+
514+
{
515+
var cppFunction = compilation.Functions[2];
516+
Assert.AreEqual("process", cppFunction.Name);
517+
Assert.AreEqual(2, cppFunction.Parameters.Count);
518+
Assert.IsNotNull(cppFunction.BodySpan, "process(int, int) should have BodySpan");
519+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
520+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
521+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
522+
}
523+
HashSet<int> startLines = new HashSet<int>();
524+
foreach (var function in compilation.Functions)
525+
{
526+
Assert.True(startLines.Add(function.BodySpan.Value.Start.Line));
527+
}
528+
}
529+
530+
[Test]
531+
public void TestMethodOverloadBodySpan()
532+
{
533+
var options = new CppParserOptions();
534+
options.ParseFunctionBodies = true;
535+
var headerFilename = "test_method_overload_body.h";
536+
537+
var text = @"
538+
class Calculator {
539+
public:
540+
int calculate(int x) {
541+
return x * 2;
542+
}
543+
544+
int calculate(float y) {
545+
return (int)(y * 3.0f);
546+
}
547+
548+
int calculate(int x, int y) {
549+
return x + y;
550+
}
551+
};
552+
";
553+
554+
var currentDirectory = Environment.CurrentDirectory;
555+
var headerFile = Path.Combine(currentDirectory, headerFilename);
556+
File.WriteAllText(headerFile, text);
557+
558+
var compilation = CppParser.ParseFile(headerFile, options);
559+
560+
Assert.False(compilation.HasErrors);
561+
Assert.AreEqual(1, compilation.Classes.Count);
562+
563+
var cls = compilation.Classes[0];
564+
Assert.AreEqual("Calculator", cls.Name);
565+
Assert.AreEqual(3, cls.Functions.Count);
566+
567+
{
568+
var cppFunction = cls.Functions[0];
569+
Assert.AreEqual("calculate", cppFunction.Name);
570+
Assert.AreEqual(1, cppFunction.Parameters.Count);
571+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(int) should have BodySpan");
572+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
573+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
574+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
575+
}
576+
577+
{
578+
var cppFunction = cls.Functions[1];
579+
Assert.AreEqual("calculate", cppFunction.Name);
580+
Assert.AreEqual(1, cppFunction.Parameters.Count);
581+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(float) should have BodySpan");
582+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
583+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
584+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
585+
}
586+
587+
{
588+
var cppFunction = cls.Functions[2];
589+
Assert.AreEqual("calculate", cppFunction.Name);
590+
Assert.AreEqual(2, cppFunction.Parameters.Count);
591+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(int, int) should have BodySpan");
592+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
593+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
594+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
595+
}
596+
597+
HashSet<int> startLines = new HashSet<int>();
598+
foreach (var function in cls.Functions)
599+
{
600+
Assert.True(startLines.Add(function.BodySpan.Value.Start.Line));
601+
}
602+
}
603+
604+
[Test]
605+
public void TestMethodOverloadDefinitionOutsideClassBodySpan()
606+
{
607+
var options = new CppParserOptions();
608+
options.ParseFunctionBodies = true;
609+
var headerFilename = "test_method_overload_outside_class_body.h";
610+
611+
var text = @"
612+
class Calculator {
613+
public:
614+
int calculate(int x);
615+
int calculate(float y);
616+
int calculate(int x, int y);
617+
};
618+
619+
int Calculator::calculate(int x)
620+
{
621+
return x * 2;
622+
}
623+
624+
int Calculator::calculate(float y)
625+
{
626+
return (int)(y * 3.0f);
627+
}
628+
629+
int Calculator::calculate(int x, int y)
630+
{
631+
return x + y;
632+
}
633+
634+
class Calculator2 {
635+
public:
636+
int calculate(int x);
637+
int calculate(float y);
638+
int calculate(int x, int y);
639+
};
640+
641+
int Calculator2::calculate(int x)
642+
{
643+
return x * 2;
644+
}
645+
646+
int Calculator2::calculate(float y)
647+
{
648+
return (int)(y * 3.0f);
649+
}
650+
651+
int Calculator2::calculate(int x, int y)
652+
{
653+
return x + y;
654+
}
655+
";
656+
657+
var currentDirectory = Environment.CurrentDirectory;
658+
var headerFile = Path.Combine(currentDirectory, headerFilename);
659+
File.WriteAllText(headerFile, text);
660+
661+
var compilation = CppParser.ParseFile(headerFile, options);
662+
663+
Assert.False(compilation.HasErrors);
664+
Assert.AreEqual(2, compilation.Classes.Count);
665+
666+
var cls = compilation.Classes[0];
667+
Assert.AreEqual("Calculator", cls.Name);
668+
Assert.AreEqual(3, cls.Functions.Count);
669+
670+
{
671+
var cppFunction = cls.Functions[0];
672+
Assert.AreEqual("calculate", cppFunction.Name);
673+
Assert.AreEqual(1, cppFunction.Parameters.Count);
674+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(int) should have BodySpan");
675+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
676+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
677+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
678+
}
679+
680+
{
681+
var cppFunction = cls.Functions[1];
682+
Assert.AreEqual("calculate", cppFunction.Name);
683+
Assert.AreEqual(1, cppFunction.Parameters.Count);
684+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(float) should have BodySpan");
685+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
686+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
687+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
688+
}
689+
690+
{
691+
var cppFunction = cls.Functions[2];
692+
Assert.AreEqual("calculate", cppFunction.Name);
693+
Assert.AreEqual(2, cppFunction.Parameters.Count);
694+
Assert.IsNotNull(cppFunction.BodySpan, "calculate(int, int) should have BodySpan");
695+
Assert.Greater(cppFunction.BodySpan.Value.Start.Line, 0);
696+
Assert.Greater(cppFunction.BodySpan.Value.End.Line, 0);
697+
Assert.GreaterOrEqual(cppFunction.BodySpan.Value.End.Offset, cppFunction.BodySpan.Value.Start.Offset);
698+
}
699+
700+
HashSet<int> startLines = new HashSet<int>();
701+
foreach (var cls2 in compilation.Classes)
702+
{
703+
foreach (var function in cls2.Functions)
704+
{
705+
Assert.True(startLines.Add(function.BodySpan.Value.Start.Line));
706+
}
707+
}
708+
}
357709

358710
}
359711
}

src/CppAst/CppFunction.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public int DefaultParamCount
9393
}
9494
}
9595

96+
/// <summary>
97+
/// Gets or sets the source span of the function body implementation.
98+
/// </summary>
99+
public CppSourceSpan? BodySpan { get; set; }
100+
96101
/// <summary>
97102
/// Gets or sets the flags of this function.
98103
/// </summary>

0 commit comments

Comments
 (0)