Browse Source

Merge pull request #57 from ddobrev/inlines

Inlines
pull/58/head
João Matos 12 years ago
parent
commit
4791894c6e
  1. 16
      src/AST/Class.cs
  2. 13
      src/AST/Function.cs
  3. 6
      src/AST/Method.cs
  4. 1
      src/AST/TranslationUnit.cs
  5. 2
      src/Generator/AST/Utils.cs
  6. 25
      src/Generator/Driver.cs
  7. 42
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  8. 49
      src/Generator/Passes/CheckIgnoredDecls.cs
  9. 8
      src/Generator/Passes/CheckOperatorsOverloads.cs
  10. 7
      src/Generator/Passes/CleanInvalidDeclNamesPass.cs
  11. 3
      src/Generator/Passes/FieldToPropertyPass.cs
  12. 6
      src/Generator/Passes/GenerateAbstractImplementationsPass.cs
  13. 103
      src/Generator/Passes/GenerateInlinesCodePass.cs
  14. 20
      src/Generator/Passes/MoveOperatorToClassPass.cs
  15. 18
      src/Generator/Utils/ParameterTypeComparer.cs
  16. 8
      tests/Basic/Basic.Tests.cs
  17. 4
      tests/Basic/Basic.h

16
src/AST/Class.cs

@ -201,6 +201,22 @@ namespace CppSharp.AST
} }
} }
public Method GetRootBaseMethod(Method @override)
{
return (from @base in Bases
let baseMethod = (
from method in @base.Class.Methods
where
method.Name == @override.Name &&
method.ReturnType == @override.ReturnType &&
method.Parameters.Count == @override.Parameters.Count &&
method.Parameters.SequenceEqual(@override.Parameters,
new ParameterTypeComparer())
select method).FirstOrDefault()
let rootBaseMethod = @base.Class.GetRootBaseMethod(@override)
select rootBaseMethod ?? baseMethod).FirstOrDefault();
}
public override T Visit<T>(IDeclVisitor<T> visitor) public override T Visit<T>(IDeclVisitor<T> visitor)
{ {
return visitor.VisitClassDecl(this); return visitor.VisitClassDecl(this);

13
src/AST/Function.cs

@ -60,6 +60,19 @@ namespace CppSharp.AST
} }
} }
public class ParameterTypeComparer : IEqualityComparer<Parameter>
{
public bool Equals(Parameter x, Parameter y)
{
return x.QualifiedType == y.QualifiedType;
}
public int GetHashCode(Parameter obj)
{
return obj.Type.GetHashCode();
}
}
public enum FunctionSynthKind public enum FunctionSynthKind
{ {
None, None,

6
src/AST/Method.cs

@ -92,6 +92,12 @@ namespace CppSharp.AST
Conversion = method.Conversion; Conversion = method.Conversion;
} }
public Method(Function function)
: base(function)
{
}
public AccessSpecifierDecl AccessDecl { get; set; } public AccessSpecifierDecl AccessDecl { get; set; }
public bool IsVirtual { get; set; } public bool IsVirtual { get; set; }

1
src/AST/TranslationUnit.cs

@ -14,6 +14,7 @@ namespace CppSharp.AST
{ {
Macros = new List<MacroDefinition>(); Macros = new List<MacroDefinition>();
FilePath = file; FilePath = file;
Access = AccessSpecifier.Public;
} }
/// Contains the macros present in the unit. /// Contains the macros present in the unit.

2
src/Generator/AST/Utils.cs

@ -37,7 +37,7 @@ namespace CppSharp.AST
if (method.Kind == CXXMethodKind.Conversion) if (method.Kind == CXXMethodKind.Conversion)
return true; return true;
if (method.Access == AccessSpecifier.Private) if (method.Access == AccessSpecifier.Private && !method.IsOverride)
return true; return true;
return false; return false;

25
src/Generator/Driver.cs

@ -133,16 +133,17 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass()); TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass());
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass());
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
TranslationUnitPasses.AddPass(new GenerateInlinesCodePass());
library.SetupPasses(this);
TranslationUnitPasses.AddPass(new FindSymbolsPass()); TranslationUnitPasses.AddPass(new FindSymbolsPass());
TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass());
TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass()); TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass());
TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance()); TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance());
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
library.SetupPasses(this);
Generator.SetupPasses(); Generator.SetupPasses();
TranslationUnitPasses.AddPass(new FieldToPropertyPass()); TranslationUnitPasses.AddPass(new FieldToPropertyPass());
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass());
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
@ -165,7 +166,7 @@ namespace CppSharp
public void WriteCode(List<GeneratorOutput> outputs) public void WriteCode(List<GeneratorOutput> outputs)
{ {
var outputPath = Options.OutputDir ?? Directory.GetCurrentDirectory(); var outputPath = Options.OutputDir;
if (!Directory.Exists(outputPath)) if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath); Directory.CreateDirectory(outputPath);
@ -208,6 +209,8 @@ namespace CppSharp
SystemIncludeDirs = new List<string>(); SystemIncludeDirs = new List<string>();
Headers = new List<string>(); Headers = new List<string>();
OutputDir = Directory.GetCurrentDirectory();
var platform = Environment.OSVersion.Platform; var platform = Environment.OSVersion.Platform;
var isUnix = platform == PlatformID.Unix || platform == PlatformID.MacOSX; var isUnix = platform == PlatformID.Unix || platform == PlatformID.MacOSX;
MicrosoftMode = !isUnix; MicrosoftMode = !isUnix;
@ -271,6 +274,20 @@ namespace CppSharp
public int MaxIndent; public int MaxIndent;
public string CommentPrefix; public string CommentPrefix;
private string inlinesLibraryName;
public string InlinesLibraryName
{
get
{
if (string.IsNullOrEmpty(inlinesLibraryName))
{
return string.Format("{0}-inlines", OutputNamespace);
}
return inlinesLibraryName;
}
set { inlinesLibraryName = value; }
}
public bool IsCSharpGenerator public bool IsCSharpGenerator
{ {
get { return GeneratorKind == LanguageGeneratorKind.CSharp; } get { return GeneratorKind == LanguageGeneratorKind.CSharp; }

42
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -899,7 +899,9 @@ namespace CppSharp.Generators.CSharp
if (prop.Ignore) continue; if (prop.Ignore) continue;
PushBlock(CSharpBlockKind.Property); PushBlock(CSharpBlockKind.Property);
WriteLine("public {0} {1}", prop.Type, SafeIdentifier(prop.Name)); WriteLine("{0} {1} {2}",
prop.Access == AccessSpecifier.Public ? "public" : "protected",
prop.Type, SafeIdentifier(prop.Name));
WriteStartBraceIndent(); WriteStartBraceIndent();
if (prop.Field != null) if (prop.Field != null)
@ -1481,8 +1483,15 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Method); PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method); GenerateDeclarationCommon(method);
Write(Driver.Options.GenerateAbstractImpls && switch (GetValidMethodAccess(method, @class))
@class.IsAbstract && method.IsConstructor ? "protected " : "public "); {
case AccessSpecifier.Public:
Write("public ");
break;
case AccessSpecifier.Protected:
Write("protected ");
break;
}
if (method.IsVirtual && !method.IsOverride && if (method.IsVirtual && !method.IsOverride &&
(!Driver.Options.GenerateAbstractImpls || !method.IsPure)) (!Driver.Options.GenerateAbstractImpls || !method.IsPure))
@ -1568,6 +1577,18 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }
private static AccessSpecifier GetValidMethodAccess(Method method, Class @class)
{
switch (method.Access)
{
case AccessSpecifier.Public:
return AccessSpecifier.Public;
default:
return method.IsOverride ?
@class.GetRootBaseMethod(method).Access : method.Access;
}
}
private void GenerateVirtualTableFunctionCall(Function method, Class @class) private void GenerateVirtualTableFunctionCall(Function method, Class @class)
{ {
string delegateId; string delegateId;
@ -1756,10 +1777,16 @@ namespace CppSharp.Generators.CSharp
var isIntPtr = retTypeName.Contains("IntPtr"); var isIntPtr = retTypeName.Contains("IntPtr");
if (retType.Type.IsPointer() && isIntPtr) Type pointee;
if (retType.Type.IsPointerTo(out pointee) && isIntPtr)
{ {
WriteLine("if ({0} == global::System.IntPtr.Zero) return null;", PrimitiveType primitive;
Generator.GeneratedIdentifier("ret")); string @null = (pointee.Desugar().IsPrimitiveType(out primitive) ||
pointee.Desugar().IsPointer()) &&
!CSharpTypePrinter.IsConstCharString(retType) ?
"IntPtr.Zero" : "null";
WriteLine("if ({0} == global::System.IntPtr.Zero) return {1};",
Generator.GeneratedIdentifier("ret"), @null);
} }
var ctx = new CSharpMarshalContext(Driver) var ctx = new CSharpMarshalContext(Driver)
@ -1953,7 +1980,8 @@ namespace CppSharp.Generators.CSharp
WriteLine("[UnmanagedFunctionPointerAttribute(CallingConvention.{0})]", WriteLine("[UnmanagedFunctionPointerAttribute(CallingConvention.{0})]",
Helpers.ToCSharpCallConv(functionType.CallingConvention)); Helpers.ToCSharpCallConv(functionType.CallingConvention));
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
WriteLine("public {0};", WriteLine("{0} {1};",
typedef.Access == AccessSpecifier.Public ? "public" : "protected",
string.Format(TypePrinter.VisitDelegate(functionType).Type, string.Format(TypePrinter.VisitDelegate(functionType).Type,
SafeIdentifier(typedef.Name))); SafeIdentifier(typedef.Name)));
TypePrinter.PopContext(); TypePrinter.PopContext();

49
src/Generator/Passes/CheckIgnoredDecls.cs

@ -5,15 +5,21 @@ namespace CppSharp.Passes
{ {
public class CheckIgnoredDeclsPass : TranslationUnitPass public class CheckIgnoredDeclsPass : TranslationUnitPass
{ {
public CheckIgnoredDeclsPass()
{
}
public override bool VisitDeclaration(Declaration decl) public override bool VisitDeclaration(Declaration decl)
{ {
if (decl.ExplicityIgnored) if (decl.ExplicityIgnored)
return false; return false;
if (decl.Access == AccessSpecifier.Private)
{
Method method = decl as Method;
if (method == null || !method.IsOverride)
{
decl.ExplicityIgnored = true;
return false;
}
}
if (decl.IsDependent) if (decl.IsDependent)
{ {
decl.ExplicityIgnored = true; decl.ExplicityIgnored = true;
@ -24,16 +30,6 @@ namespace CppSharp.Passes
return true; return true;
} }
public override bool VisitClassDecl(Class @class)
{
if (@class.Access == AccessSpecifier.Private)
{
@class.ExplicityIgnored = true;
return false;
}
return base.VisitClassDecl(@class);
}
public override bool VisitFieldDecl(Field field) public override bool VisitFieldDecl(Field field)
{ {
if (!VisitDeclaration(field)) if (!VisitDeclaration(field))
@ -86,6 +82,20 @@ namespace CppSharp.Passes
function.Name, msg); function.Name, msg);
return false; return false;
} }
if (param.Kind == ParameterKind.IndirectReturnType)
{
Class retClass;
param.Type.Desugar().IsTagDecl(out retClass);
if (retClass == null)
{
function.ExplicityIgnored = true;
Driver.Diagnostics.EmitWarning(
"Function '{0}' was ignored due to an indirect return param not of a tag type",
function.Name);
return false;
}
}
} }
return true; return true;
@ -93,16 +103,7 @@ namespace CppSharp.Passes
public override bool VisitMethodDecl(Method method) public override bool VisitMethodDecl(Method method)
{ {
if (!VisitDeclaration(method)) return VisitDeclaration(method) && base.VisitMethodDecl(method);
return false;
if (method.Access == AccessSpecifier.Private)
{
method.ExplicityIgnored = true;
return false;
}
return base.VisitMethodDecl(method);
} }
public override bool VisitTypedefDecl(TypedefDecl typedef) public override bool VisitTypedefDecl(TypedefDecl typedef)

8
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -54,6 +54,8 @@ namespace CppSharp.Passes
@operator.ExplicityIgnored = true; @operator.ExplicityIgnored = true;
continue; continue;
} }
if (@operator.SynthKind == FunctionSynthKind.NonMemberOperator)
continue;
// Handle missing operator parameters // Handle missing operator parameters
if (@operator.IsStatic) if (@operator.IsStatic)
@ -84,10 +86,8 @@ namespace CppSharp.Passes
var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2, var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2,
op.Parameters.Last().Type); op.Parameters.Last().Type);
if (missingKind == CXXOperatorKind.None) if (missingKind == CXXOperatorKind.None || op.Ignore)
return; continue;
if (op.Ignore) continue;
var method = new Method() var method = new Method()
{ {

7
src/Generator/Passes/CleanInvalidDeclNamesPass.cs

@ -34,6 +34,13 @@ namespace CppSharp.Passes
if (decl is Namespace) if (decl is Namespace)
return true; return true;
// types with empty names are assumed to be private
if (decl is Class && string.IsNullOrWhiteSpace(decl.Name))
{
decl.ExplicityIgnored = true;
return false;
}
decl.Name = CheckName(decl.Name); decl.Name = CheckName(decl.Name);
StringHelpers.CleanupText(ref decl.DebugText); StringHelpers.CleanupText(ref decl.DebugText);

3
src/Generator/Passes/FieldToPropertyPass.cs

@ -16,11 +16,12 @@ namespace CppSharp.Passes
if (ASTUtils.CheckIgnoreField(field)) if (ASTUtils.CheckIgnoreField(field))
return false; return false;
var prop = new Property() var prop = new Property
{ {
Name = field.Name, Name = field.Name,
Namespace = field.Namespace, Namespace = field.Namespace,
QualifiedType = field.QualifiedType, QualifiedType = field.QualifiedType,
Access = field.Access,
Field = field Field = field
}; };
@class.Properties.Add(prop); @class.Properties.Add(prop);

6
src/Generator/Passes/GenerateAbstractImplementationsPass.cs

@ -34,7 +34,13 @@ namespace CppSharp.Passes
return false; return false;
if (@class.IsAbstract) if (@class.IsAbstract)
{
foreach (var ctor in from ctor in @class.Constructors
where ctor.Access == AccessSpecifier.Public
select ctor)
ctor.Access = AccessSpecifier.Protected;
internalImpls.Add(AddInternalImplementation(@class)); internalImpls.Add(AddInternalImplementation(@class));
}
return base.VisitClassDecl(@class); return base.VisitClassDecl(@class);
} }

103
src/Generator/Passes/GenerateInlinesCodePass.cs

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using CppSharp.AST;
namespace CppSharp.Passes
{
public class GenerateInlinesCodePass : TranslationUnitPass
{
private TranslationUnit currentUnit;
private readonly List<string> headers = new List<string>();
private readonly List<string> mangledInlines = new List<string>();
public override bool VisitLibrary(Library library)
{
bool result = base.VisitLibrary(library);
Directory.CreateDirectory(Driver.Options.OutputDir);
WriteInlinesIncludes();
WriteInlinedSymbols();
return result;
}
private void WriteInlinesIncludes()
{
var cppBuilder = new StringBuilder();
headers.Sort();
foreach (var header in headers)
cppBuilder.AppendFormat("#include \"{0}\"\n", header);
var cpp = string.Format("{0}.cpp", Driver.Options.InlinesLibraryName);
var path = Path.Combine(Driver.Options.OutputDir, cpp);
File.WriteAllText(path, cppBuilder.ToString());
}
private void WriteInlinedSymbols()
{
switch (Driver.Options.Abi)
{
case CppAbi.Microsoft:
var defBuilder = new StringBuilder("EXPORTS\r\n");
for (int i = 0; i < mangledInlines.Count; i++)
defBuilder.AppendFormat(" {0} @{1}\r\n",
mangledInlines[i], i + 1);
var def = string.Format("{0}.def", Driver.Options.InlinesLibraryName);
File.WriteAllText(Path.Combine(Driver.Options.OutputDir, def),
defBuilder.ToString());
break;
default:
var symbolsBuilder = new StringBuilder();
foreach (var mangledInline in mangledInlines)
symbolsBuilder.AppendFormat("{0}\n", mangledInline);
var txt = string.Format("{0}.txt", Driver.Options.InlinesLibraryName);
File.WriteAllText(Path.Combine(Driver.Options.OutputDir, txt),
symbolsBuilder.ToString());
break;
}
}
public override bool VisitTranslationUnit(TranslationUnit unit)
{
currentUnit = unit;
return base.VisitTranslationUnit(unit);
}
public override bool VisitFunctionDecl(Function function)
{
CheckForSymbols(function);
return base.VisitFunctionDecl(function);
}
public override bool VisitVariableDecl(Variable variable)
{
CheckForSymbols(variable);
return base.VisitVariableDecl(variable);
}
private void CheckForSymbols(IMangledDecl mangled)
{
string symbol = mangled.Mangled;
var declaration = (Declaration) mangled;
if (!declaration.Ignore && AccessValid(declaration) &&
!Driver.LibrarySymbols.FindSymbol(ref symbol) &&
!currentUnit.FilePath.EndsWith("_impl.h") &&
!currentUnit.FilePath.EndsWith("_p.h"))
{
if (!headers.Contains(currentUnit.FileName))
headers.Add(currentUnit.FileName);
if (!mangledInlines.Contains(mangled.Mangled))
mangledInlines.Add(mangled.Mangled);
}
}
private static bool AccessValid(Declaration declaration)
{
if (declaration.Access == AccessSpecifier.Private)
{
var method = declaration as Method;
return method != null && method.IsOverride;
}
return true;
}
}
}

20
src/Generator/Passes/MoveOperatorToClassPass.cs

@ -23,28 +23,20 @@ namespace CppSharp.Passes
if (!FunctionToInstanceMethodPass.GetClassParameter(param, out @class)) if (!FunctionToInstanceMethodPass.GetClassParameter(param, out @class))
return false; return false;
function.ExplicityIgnored = true;
// Create a new fake method so it acts as a static method. // Create a new fake method so it acts as a static method.
var method = new Method()
var method = new Method(function)
{ {
Namespace = @class, Namespace = @class,
OriginalNamespace = function.Namespace,
Name = function.Name,
OriginalName = function.OriginalName,
Mangled = function.Mangled,
Access = AccessSpecifier.Public,
Kind = CXXMethodKind.Operator, Kind = CXXMethodKind.Operator,
ReturnType = function.ReturnType,
Parameters = new List<Parameter>(function.Parameters).Skip(1).ToList(),
CallingConvention = function.CallingConvention,
IsVariadic = function.IsVariadic,
IsInline = function.IsInline,
OperatorKind = function.OperatorKind, OperatorKind = function.OperatorKind,
SynthKind = FunctionSynthKind.NonMemberOperator, SynthKind = FunctionSynthKind.NonMemberOperator,
OriginalFunction = function OriginalFunction = null,
IsStatic = true
}; };
function.ExplicityIgnored = true;
@class.Methods.Add(method); @class.Methods.Add(method);
Driver.Diagnostics.Debug("Function converted to operator: {0}::{1}", Driver.Diagnostics.Debug("Function converted to operator: {0}::{1}",

18
src/Generator/Utils/ParameterTypeComparer.cs

@ -1,18 +0,0 @@
using System.Collections.Generic;
using CppSharp.AST;
namespace CppSharp.Utils
{
public class ParameterTypeComparer : IEqualityComparer<Parameter>
{
public bool Equals(Parameter x, Parameter y)
{
return x.QualifiedType == y.QualifiedType;
}
public int GetHashCode(Parameter obj)
{
return obj.Type.GetHashCode();
}
}
}

8
tests/Basic/Basic.Tests.cs

@ -1,3 +1,4 @@
using System.Reflection;
using NUnit.Framework; using NUnit.Framework;
using Basic; using Basic;
@ -95,5 +96,12 @@ public class BasicTests
Assert.AreEqual(abstractFoo.pureFunction1(), 10); Assert.AreEqual(abstractFoo.pureFunction1(), 10);
Assert.AreEqual(abstractFoo.pureFunction2(), 15); Assert.AreEqual(abstractFoo.pureFunction2(), 15);
} }
[Test, Ignore]
public void TestPropertyAccessModifier()
{
Assert.That(typeof(Foo2).GetProperty("P",
BindingFlags.Instance | BindingFlags.NonPublic), Is.Not.Null);
}
} }

4
tests/Basic/Basic.h

@ -25,6 +25,10 @@ public:
Foo2 operator<<(signed int i); Foo2 operator<<(signed int i);
Foo2 operator<<(signed long l); Foo2 operator<<(signed long l);
// TODO: uncomment when the C++/CLI back-end supports protected members
//protected:
// int P;
}; };
struct DLL_API Bar struct DLL_API Bar

Loading…
Cancel
Save