Browse Source

Merge pull request #229 from azeno/unnamed-enum-support

Unnamed enum support
pull/242/merge
João Matos 11 years ago
parent
commit
8658a6b731
  1. 12
      src/AST/Namespace.cs
  2. 2
      src/Core/Parser/ASTConverter.cs
  3. 43
      src/CppParser/AST.cpp
  4. 4
      src/CppParser/AST.h
  5. 32
      src/CppParser/Parser.cpp
  6. 8
      src/Generator.Tests/AST/TestAST.cs
  7. 35
      src/Generator.Tests/Passes/TestPasses.cs
  8. 22
      src/Generator/Passes/CleanInvalidDeclNamesPass.cs
  9. 30
      src/Parser/Parser.cpp
  10. 3
      tests/Native/AST.h
  11. 9
      tests/Native/Enums.h
  12. 12
      tests/Native/Passes.h

12
src/AST/Namespace.cs

@ -180,6 +180,11 @@ namespace CppSharp.AST
return @namespace.FindEnum(enumName, createDecl); return @namespace.FindEnum(enumName, createDecl);
} }
public Enumeration FindEnum(IntPtr ptr)
{
return Enums.FirstOrDefault(f => f.OriginalPtr == ptr);
}
public Function FindFunction(string name, bool createDecl = false) public Function FindFunction(string name, bool createDecl = false)
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
@ -348,7 +353,12 @@ namespace CppSharp.AST
public Enumeration FindEnumWithItem(string name) public Enumeration FindEnumWithItem(string name)
{ {
return Enums.Find(e => e.ItemsByName.ContainsKey(name)); var result = Enums.Find(e => e.ItemsByName.ContainsKey(name));
if (result == null)
result = Namespaces.Select(ns => ns.FindEnumWithItem(name)).FirstOrDefault();
if (result == null)
result = Classes.Select(c => c.FindEnumWithItem(name)).FirstOrDefault();
return result;
} }
public virtual IEnumerable<Function> FindOperator(CXXOperatorKind kind) public virtual IEnumerable<Function> FindOperator(CXXOperatorKind kind)

2
src/Core/Parser/ASTConverter.cs

@ -1023,7 +1023,7 @@ namespace CppSharp
{ {
var item = decl.getItems(i); var item = decl.getItems(i);
var _item = Visit(item) as AST.Enumeration.Item; var _item = Visit(item) as AST.Enumeration.Item;
_enum.Items.Add(_item); _enum.AddItem(_item);
} }
return _enum; return _enum;

43
src/CppParser/AST.cpp

@ -270,6 +270,17 @@ Class* DeclarationContext::FindClass(const std::string& Name, bool IsComplete,
return newClass; return newClass;
} }
Enumeration* DeclarationContext::FindEnum(void* OriginalPtr)
{
auto foundEnum = std::find_if(Enums.begin(), Enums.end(),
[&](Enumeration* enumeration) { return enumeration->OriginalPtr == OriginalPtr; });
if (foundEnum != Enums.end())
return *foundEnum;
return nullptr;
}
Enumeration* DeclarationContext::FindEnum(const std::string& Name, bool Create) Enumeration* DeclarationContext::FindEnum(const std::string& Name, bool Create)
{ {
auto entries = split<std::string>(Name, "::"); auto entries = split<std::string>(Name, "::");
@ -304,6 +315,27 @@ Enumeration* DeclarationContext::FindEnum(const std::string& Name, bool Create)
return _namespace->FindEnum(enumName, Create); return _namespace->FindEnum(enumName, Create);
} }
Enumeration* DeclarationContext::FindEnumWithItem(const std::string& Name)
{
auto foundEnumIt = std::find_if(Enums.begin(), Enums.end(),
[&](Enumeration* _enum) { return _enum->FindItemByName(Name) != nullptr; });
if (foundEnumIt != Enums.end())
return *foundEnumIt;
for (auto it = Namespaces.begin(); it != Namespaces.end(); ++it)
{
auto foundEnum = (*it)->FindEnumWithItem(Name);
if (foundEnum != nullptr)
return foundEnum;
}
for (auto it = Classes.begin(); it != Classes.end(); ++it)
{
auto foundEnum = (*it)->FindEnumWithItem(Name);
if (foundEnum != nullptr)
return foundEnum;
}
return nullptr;
}
Function* DeclarationContext::FindFunction(const std::string& Name, bool Create) Function* DeclarationContext::FindFunction(const std::string& Name, bool Create)
{ {
auto foundFunction = std::find_if(Functions.begin(), Functions.end(), auto foundFunction = std::find_if(Functions.begin(), Functions.end(),
@ -384,6 +416,8 @@ DEF_VECTOR(Function, Parameter*, Parameters)
Method::Method() : IsDefaultConstructor(false), IsCopyConstructor(false), Method::Method() : IsDefaultConstructor(false), IsCopyConstructor(false),
IsMoveConstructor(false) { Kind = DeclarationKind::Method; } IsMoveConstructor(false) { Kind = DeclarationKind::Method; }
// Enumeration
Enumeration::Enumeration() : Declaration(DeclarationKind::Enumeration), Enumeration::Enumeration() : Declaration(DeclarationKind::Enumeration),
Modifiers((EnumModifiers)0), Type(0), BuiltinType(0) {} Modifiers((EnumModifiers)0), Type(0), BuiltinType(0) {}
@ -396,6 +430,15 @@ Enumeration::Item::Item(const Item& rhs) : Declaration(rhs),
DEF_STRING(Enumeration::Item, Expression) DEF_STRING(Enumeration::Item, Expression)
Enumeration::Item* Enumeration::FindItemByName(const std::string& Name)
{
auto foundEnumItem = std::find_if(Items.begin(), Items.end(),
[&](Item _item) { return _item.Name == Name; });
if (foundEnumItem != Items.end())
return &*foundEnumItem;
return nullptr;
}
Variable::Variable() : Declaration(DeclarationKind::Variable) {} Variable::Variable() : Declaration(DeclarationKind::Variable) {}
DEF_STRING(Variable, Mangled) DEF_STRING(Variable, Mangled)

4
src/CppParser/AST.h

@ -402,7 +402,9 @@ struct CS_API DeclarationContext : public Declaration
CS_IGNORE FunctionTemplate* FindFunctionTemplate(const std::string& Name, CS_IGNORE FunctionTemplate* FindFunctionTemplate(const std::string& Name,
const std::vector<TemplateParameter>& Params); const std::vector<TemplateParameter>& Params);
CS_IGNORE Enumeration* FindEnum(void* OriginalPtr);
CS_IGNORE Enumeration* FindEnum(const std::string& Name, bool Create = false); CS_IGNORE Enumeration* FindEnum(const std::string& Name, bool Create = false);
CS_IGNORE Enumeration* FindEnumWithItem(const std::string& Name);
CS_IGNORE Function* FindFunction(const std::string& Name, bool Create = false); CS_IGNORE Function* FindFunction(const std::string& Name, bool Create = false);
@ -560,6 +562,8 @@ struct CS_API Enumeration : public Declaration
CppSharp::CppParser::AST::Type* Type; CppSharp::CppParser::AST::Type* Type;
CppSharp::CppParser::AST::BuiltinType* BuiltinType; CppSharp::CppParser::AST::BuiltinType* BuiltinType;
VECTOR(Item, Items) VECTOR(Item, Items)
Item* FindItemByName(const std::string& Name);
}; };
struct CS_API Variable : public Declaration struct CS_API Variable : public Declaration

32
src/CppParser/Parser.cpp

@ -1705,18 +1705,48 @@ Type* Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL,
Enumeration* Parser::WalkEnum(clang::EnumDecl* ED) Enumeration* Parser::WalkEnum(clang::EnumDecl* ED)
{ {
using namespace clang;
auto NS = GetNamespace(ED); auto NS = GetNamespace(ED);
assert(NS && "Expected a valid namespace"); assert(NS && "Expected a valid namespace");
auto E = NS->FindEnum(ED->getCanonicalDecl());
if (E && !E->IsIncomplete)
return E;
if (!E)
{
auto Name = GetTagDeclName(ED); auto Name = GetTagDeclName(ED);
auto E = NS->FindEnum(Name, /*Create=*/false); if (!Name.empty())
E = NS->FindEnum(Name, /*Create=*/false);
else
{
// Enum with no identifier - try to find existing enum through enum items
for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); ++it)
{
EnumConstantDecl* ECD = (*it);
auto EnumItemName = ECD->getNameAsString();
E = NS->FindEnumWithItem(EnumItemName);
break;
}
}
}
if (E && !E->IsIncomplete) if (E && !E->IsIncomplete)
return E; return E;
if (!E) if (!E)
{ {
auto Name = GetTagDeclName(ED);
if (!Name.empty())
E = NS->FindEnum(Name, /*Create=*/true); E = NS->FindEnum(Name, /*Create=*/true);
else
{
E = new Enumeration();
E->Name = Name;
E->_Namespace = NS;
NS->Enums.push_back(E);
}
HandleDeclaration(ED, E); HandleDeclaration(ED, E);
} }

8
src/Generator.Tests/AST/TestAST.cs

@ -160,5 +160,13 @@ namespace CppSharp.Generator.Tests.AST
.First(); .First();
Assert.IsTrue(plusOperator.Visit(testVisitor)); Assert.IsTrue(plusOperator.Visit(testVisitor));
} }
[Test]
public void TestASTEnumItemByName()
{
var @enum = AstContext.FindEnum("TestASTEnumItemByName").Single();
Assert.NotNull(@enum);
Assert.IsTrue(@enum.ItemsByName.ContainsKey("TestItemByName"));
}
} }
} }

35
src/Generator.Tests/Passes/TestPasses.cs

@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using CppSharp;
using CppSharp.Passes; using CppSharp.Passes;
using NUnit.Framework; using NUnit.Framework;
@ -95,6 +96,40 @@ namespace CppSharp.Generator.Tests.Passes
Assert.That(@enum.Items[0].Name, Is.EqualTo("_0")); Assert.That(@enum.Items[0].Name, Is.EqualTo("_0"));
} }
[Test]
public void TestUnnamedEnumSupport()
{
passBuilder.AddPass(new CleanInvalidDeclNamesPass());
passBuilder.RunPasses(pass => pass.VisitLibrary(AstContext));
var unnamedEnum1 = AstContext.FindEnum("Unnamed_Enum_1").Single();
var unnamedEnum2 = AstContext.FindEnum("Unnamed_Enum_2").Single();
Assert.IsNotNull(unnamedEnum1);
Assert.IsNotNull(unnamedEnum2);
Assert.AreEqual(2, unnamedEnum1.Items.Count);
Assert.AreEqual(2, unnamedEnum2.Items.Count);
Assert.AreEqual(1, unnamedEnum1.Items[0].Value);
Assert.AreEqual(2, unnamedEnum1.Items[1].Value);
Assert.AreEqual(3, unnamedEnum2.Items[0].Value);
Assert.AreEqual(4, unnamedEnum2.Items[1].Value);
}
[Test]
public void TestUniqueNamesAcrossTranslationUnits()
{
passBuilder.AddPass(new CleanInvalidDeclNamesPass());
passBuilder.RunPasses(pass => pass.VisitLibrary(AstContext));
var unnamedEnum1 = AstContext.GetEnumWithMatchingItem("UnnamedEnumA1");
var unnamedEnum2 = AstContext.GetEnumWithMatchingItem("UnnamedEnumB1");
Assert.IsNotNull(unnamedEnum1);
Assert.IsNotNull(unnamedEnum2);
Assert.AreNotEqual(unnamedEnum1.Name, unnamedEnum2.Name);
}
[Test] [Test]
public void TestStructInheritance() public void TestStructInheritance()
{ {

22
src/Generator/Passes/CleanInvalidDeclNamesPass.cs

@ -68,23 +68,30 @@ namespace CppSharp.Passes
} }
} }
return base.VisitClassDecl(@class); var currentUniqueName = this.uniqueName;
this.uniqueName = 0;
var ret = base.VisitClassDecl(@class);
this.uniqueName = currentUniqueName;
return ret;
} }
public override bool VisitFunctionDecl(Function function) public override bool VisitFunctionDecl(Function function)
{ {
uniqueName = 0; var currentUniqueName = this.uniqueName;
this.uniqueName = 0;
var ret = base.VisitFunctionDecl(function); var ret = base.VisitFunctionDecl(function);
uniqueName = 0; this.uniqueName = currentUniqueName;
return ret; return ret;
} }
public override bool VisitEvent(Event @event) public override bool VisitEvent(Event @event)
{ {
uniqueName = 0; var currentUniqueName = this.uniqueName;
this.uniqueName = 0;
var ret = base.VisitEvent(@event); var ret = base.VisitEvent(@event);
uniqueName = 0; this.uniqueName = currentUniqueName;
return ret; return ret;
} }
@ -92,9 +99,10 @@ namespace CppSharp.Passes
public override bool VisitFunctionType(FunctionType type, public override bool VisitFunctionType(FunctionType type,
TypeQualifiers quals) TypeQualifiers quals)
{ {
uniqueName = 0; var currentUniqueName = this.uniqueName;
this.uniqueName = 0;
var ret = base.VisitFunctionType(type, quals); var ret = base.VisitFunctionType(type, quals);
uniqueName = 0; this.uniqueName = currentUniqueName;
return ret; return ret;
} }

30
src/Parser/Parser.cpp

@ -1719,15 +1719,43 @@ CppSharp::AST::Enumeration^ Parser::WalkEnum(clang::EnumDecl* ED)
auto NS = GetNamespace(ED); auto NS = GetNamespace(ED);
assert(NS && "Expected a valid namespace"); assert(NS && "Expected a valid namespace");
auto E = NS->FindEnum(System::IntPtr(ED->getCanonicalDecl()));
if (E && !E->IsIncomplete)
return E;
if (!E)
{
auto Name = marshalString<E_UTF8>(GetTagDeclName(ED)); auto Name = marshalString<E_UTF8>(GetTagDeclName(ED));
auto E = NS->FindEnum(Name, /*Create=*/false); if (!System::String::IsNullOrEmpty(Name))
E = NS->FindEnum(Name, /*Create=*/false);
else
{
// Enum with no identifier - try to find existing enum through enum items
for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); ++it)
{
EnumConstantDecl* ECD = (*it);
auto EnumItemName = marshalString<E_UTF8>(ECD->getNameAsString());
E = NS->FindEnumWithItem(EnumItemName);
break;
}
}
}
if (E && !E->IsIncomplete) if (E && !E->IsIncomplete)
return E; return E;
if (!E) if (!E)
{ {
auto Name = marshalString<E_UTF8>(GetTagDeclName(ED));
if (!System::String::IsNullOrEmpty(Name))
E = NS->FindEnum(Name, /*Create=*/true); E = NS->FindEnum(Name, /*Create=*/true);
else
{
E = gcnew CppSharp::AST::Enumeration();
E->Name = Name;
E->Namespace = NS;
NS->Enums->Add(E);
}
HandleDeclaration(ED, E); HandleDeclaration(ED, E);
} }

3
tests/Native/AST.h

@ -20,3 +20,6 @@ namespace Math
return Complex(re + other.re, im + other.im); return Complex(re + other.re, im + other.im);
} }
} }
// Tests Enum.ItemByName
enum TestASTEnumItemByName { TestItemByName };

9
tests/Native/Enums.h

@ -0,0 +1,9 @@
enum
{
UnnamedEnumA1,
EnumUnnamedA2
};
// This line will make sure that a visitor won't enumerate all enums across
// different translation units at once.
struct TestUniqueNames {};

12
tests/Native/Passes.h

@ -40,3 +40,15 @@ struct TestReadOnlyProperties
// TestStructInheritance // TestStructInheritance
struct S1 { int F1, F2; }; struct S1 { int F1, F2; };
struct S2 : S1 { int F3; }; struct S2 : S1 { int F3; };
// Tests unnamed enums
enum { Unnamed_Enum_1_A = 1, Unnamed_Enum_1_B = 2 };
enum { Unnamed_Enum_2_A = 3, Unnamed_Enum_2_B = 4 };
// Tests unique name for unnamed enums across translation units
#include "Enums.h"
enum
{
UnnamedEnumB1,
EnumUnnamedB2
};

Loading…
Cancel
Save