Browse Source

Added the new C++/CLI free parser.

I benchmarked it and it's about the same speed in Release mode (maybe a bit faster) but 3x slower in VS Debug mode due to all the STL usage.
pull/72/merge
triton 12 years ago
parent
commit
62839a3f0a
  1. 260
      src/CppParser/AST.cpp
  2. 599
      src/CppParser/AST.h
  3. 48
      src/CppParser/CXXABI.h
  4. 283
      src/CppParser/Comments.cpp
  5. 94
      src/CppParser/CppParser.h
  6. 2370
      src/CppParser/Parser.cpp
  7. 118
      src/CppParser/Parser.h
  8. 257
      src/CppParser/VSLookup.cpp
  9. 88
      src/CppParser/premake4.lua

260
src/CppParser/AST.cpp

@ -0,0 +1,260 @@ @@ -0,0 +1,260 @@
/************************************************************************
*
* CppSharp
* Licensed under the MIT license.
*
************************************************************************/
#include "AST.h"
#include <algorithm>
#include <string>
#include <vector>
template<typename T>
static std::vector<T> split(const T & str, const T & delimiters) {
std::vector<T> v;
T::size_type start = 0;
auto pos = str.find_first_of(delimiters, start);
while(pos != T::npos) {
if(pos != start) // ignore empty tokens
v.emplace_back(str, start, pos - start);
start = pos + 1;
pos = str.find_first_of(delimiters, start);
}
if(start < str.length()) // ignore trailing delimiter
// add what's left of the string
v.emplace_back(str, start, str.length() - start);
return v;
}
namespace CppSharp { namespace CppParser {
Declaration* DeclarationContext::FindAnonymous(uint64_t key)
{
auto it = Anonymous.find(key);
return (it != Anonymous.end()) ? it->second : 0;
}
Namespace* DeclarationContext::FindNamespace(const std::string& Name)
{
auto namespaces = split<std::string>(Name, "::");
return FindNamespace(namespaces);
}
Namespace*
DeclarationContext::FindNamespace(const std::vector<std::string>& Namespaces)
{
auto currentNamespace = this;
for (auto I = Namespaces.begin(), E = Namespaces.end(); I != E; ++I)
{
auto& _namespace = *I;
auto childNamespace = std::find_if(currentNamespace->Namespaces.begin(),
currentNamespace->Namespaces.end(),
[&](CppSharp::CppParser::Namespace* ns) {
return ns->Name == _namespace;
});
if (childNamespace == currentNamespace->Namespaces.end())
return nullptr;
currentNamespace = *childNamespace;
}
return (CppSharp::CppParser::Namespace*) currentNamespace;
}
Namespace* DeclarationContext::FindCreateNamespace(const std::string& Name)
{
auto _namespace = FindNamespace(Name);
if (!_namespace)
{
_namespace = new Namespace();
_namespace->Name = Name;
_namespace->_Namespace = this;
Namespaces.push_back(_namespace);
}
return _namespace;
}
Class* DeclarationContext::FindClass(const std::string& Name)
{
if (Name.empty()) return nullptr;
auto entries = split<std::string>(Name, "::");
if (entries.size() == 1)
{
auto _class = std::find_if(Classes.begin(), Classes.end(),
[&](Class* klass) { return klass->Name == Name; });
return _class != Classes.end() ? *_class : nullptr;
}
auto className = entries[entries.size() - 1];
std::vector<std::string> namespaces;
std::copy_n(entries.begin(), entries.size() - 1, std::back_inserter(namespaces));
auto _namespace = FindNamespace(namespaces);
if (!_namespace)
return nullptr;
return _namespace->FindClass(className);
}
Class* DeclarationContext::CreateClass(std::string Name, bool IsComplete)
{
auto _class = new Class();
_class->Name = Name;
_class->_Namespace = this;
_class->IsIncomplete = !IsComplete;
return _class;
}
Class* DeclarationContext::FindClass(const std::string& Name, bool IsComplete,
bool Create)
{
auto _class = FindClass(Name);
if (!_class)
{
if (Create)
{
_class = CreateClass(Name, IsComplete);
Classes.push_back(_class);
}
return _class;
}
if (_class->IsIncomplete == !IsComplete)
return _class;
if (!Create)
return nullptr;
auto newClass = CreateClass(Name, IsComplete);
// Replace the incomplete declaration with the complete one.
if (_class->IsIncomplete)
{
_class->CompleteDeclaration = newClass;
std::replace_if(Classes.begin(), Classes.end(),
[&](Class* klass) { return klass == _class; }, newClass);
}
return newClass;
}
Enumeration* DeclarationContext::FindEnum(const std::string& Name, bool Create)
{
if (Name.empty()) return nullptr;
auto entries = split<std::string>(Name, "::");
if (entries.size() == 1)
{
auto foundEnum = std::find_if(Enums.begin(), Enums.end(),
[&](Enumeration* _enum) { return _enum->Name == Name; });
if (foundEnum != Enums.end())
return *foundEnum;
if (!Create)
return nullptr;
auto _enum = new Enumeration();
_enum->Name = Name;
_enum->_Namespace = this;
Enums.push_back(_enum);
return _enum;
}
auto enumName = entries[entries.size() - 1];
std::vector<std::string> namespaces;
std::copy_n(entries.begin(), entries.size() - 1, std::back_inserter(namespaces));
auto _namespace = FindNamespace(namespaces);
if (!_namespace)
return nullptr;
return _namespace->FindEnum(enumName, Create);
}
Function* DeclarationContext::FindFunction(const std::string& Name, bool Create)
{
auto foundFunction = std::find_if(Functions.begin(), Functions.end(),
[&](Function* func) { return func->Name == Name; });
if (foundFunction != Functions.end())
return *foundFunction;
if (!Create)
return nullptr;
auto function = new Function();
function->Name = Name;
function->_Namespace = this;
Functions.push_back(function);
return function;
}
TypedefDecl* DeclarationContext::FindTypedef(const std::string& Name, bool Create)
{
auto foundTypedef = std::find_if(Typedefs.begin(), Typedefs.end(),
[&](TypedefDecl* tdef) { return tdef->Name == Name; });
if (foundTypedef != Typedefs.end())
return *foundTypedef;
if (!Create)
return nullptr;
auto tdef = new TypedefDecl();
tdef->Name = Name;
tdef->_Namespace = this;
Typedefs.push_back(tdef);
return tdef;
}
TranslationUnit* Library::FindOrCreateModule(const std::string& File)
{
auto existingUnit = std::find_if(TranslationUnits.begin(),
TranslationUnits.end(), [&](TranslationUnit* unit) {
return unit && unit->FileName == File;
});
if (existingUnit != TranslationUnits.end())
return *existingUnit;
auto unit = new TranslationUnit();
unit->FileName = File;
TranslationUnits.push_back(unit);
return unit;
}
NativeLibrary* Library::FindOrCreateLibrary(const std::string& File)
{
auto existingLib = std::find_if(Libraries.begin(),
Libraries.end(), [&](NativeLibrary* lib) {
return lib && lib->FileName == File;
});
auto lib = new NativeLibrary();
lib->FileName = File;
Libraries.push_back(lib);
return lib;
}
} }

599
src/CppParser/AST.h

@ -0,0 +1,599 @@ @@ -0,0 +1,599 @@
/************************************************************************
*
* CppSharp
* Licensed under the MIT license.
*
************************************************************************/
#pragma once
#include <cstdint>
#include <vector>
#include <map>
#include <string>
#define CS_FLAGS
#if defined(_MSC_VER) && !defined(__clang__)
#define CS_API __declspec(dllexport)
#else
#define CS_API
#endif
namespace CppSharp { namespace CppParser {
// Types
struct CS_API Type
{
};
struct CS_API TypeQualifiers
{
bool IsConst;
bool IsVolatile;
bool IsRestrict;
};
struct CS_API QualifiedType
{
Type* Type;
TypeQualifiers Qualifiers;
};
struct Declaration;
struct CS_API TagType : public Type
{
Declaration* Declaration;
};
struct CS_API ArrayType : public Type
{
enum class ArraySize
{
Constant,
Variable,
Dependent,
Incomplete
};
QualifiedType QualifiedType;
ArraySize SizeType;
long Size;
};
struct Parameter;
enum class CallingConvention
{
Default,
C,
StdCall,
ThisCall,
FastCall,
Unknown
};
struct CS_API FunctionType : public Type
{
QualifiedType ReturnType;
std::vector<Parameter*> Parameters;
CallingConvention CallingConvention;
};
struct CS_API PointerType : public Type
{
enum struct TypeModifier
{
Value,
Pointer,
LVReference,
RVReference
};
QualifiedType QualifiedPointee;
TypeModifier Modifier;
};
struct CS_API MemberPointerType : public Type
{
QualifiedType Pointee;
};
struct TypedefDecl;
struct CS_API TypedefType : public Type
{
TypedefDecl* Declaration;
};
struct CS_API DecayedType : public Type
{
QualifiedType Decayed;
QualifiedType Original;
QualifiedType Pointee;
};
struct CS_API TemplateArgument
{
enum struct ArgumentKind
{
Type,
Declaration,
NullPtr,
Integral,
Template,
TemplateExpansion,
Expression,
Pack
};
ArgumentKind Kind;
QualifiedType Type;
Declaration* Declaration;
long Integral;
};
struct Template;
struct CS_API TemplateSpecializationType : public Type
{
std::vector<TemplateArgument> Arguments;
Template* Template;
Type* Desugared;
};
struct CS_API TemplateParameter
{
std::string Name;
};
struct CS_API TemplateParameterType : public Type
{
TemplateParameter Parameter;
};
struct CS_API TemplateParameterSubstitutionType : public Type
{
QualifiedType Replacement;
};
struct Class;
struct CS_API InjectedClassNameType : public Type
{
TemplateSpecializationType TemplateSpecialization;
Class* Class;
};
struct CS_API DependentNameType : public Type
{
};
enum struct PrimitiveType
{
Null,
Void,
Bool,
WideChar,
Int8,
Char = Int8,
UInt8,
UChar = UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float,
Double,
IntPtr
};
struct CS_API BuiltinType : public Type
{
PrimitiveType Type;
};
// Comments
enum struct RawCommentKind
{
Invalid,
OrdinaryBCPL,
OrdinaryC,
BCPLSlash,
BCPLExcl,
JavaDoc,
Qt,
Merged
};
struct FullComment;
struct CS_API RawComment
{
RawCommentKind Kind;
std::string Text;
std::string BriefText;
FullComment* FullComment;
};
// Class layouts
enum struct VTableComponentKind
{
VCallOffset,
VBaseOffset,
OffsetToTop,
RTTI,
FunctionPointer,
CompleteDtorPointer,
DeletingDtorPointer,
UnusedFunctionPointer,
};
struct CS_API VTableComponent
{
VTableComponentKind Kind;
unsigned Offset;
Declaration* Declaration;
};
struct CS_API VTableLayout
{
std::vector<VTableComponent> Components;
};
struct CS_API VFTableInfo
{
uint64_t VBTableIndex;
uint32_t VFPtrOffset;
uint32_t VFPtrFullOffset;
VTableLayout Layout;
};
enum struct CppAbi
{
Itanium,
Microsoft,
ARM
};
struct CS_API ClassLayout
{
CppAbi ABI;
std::vector<VFTableInfo> VFTables;
VTableLayout Layout;
bool HasOwnVFPtr;
long VBPtrOffset;
int Alignment;
int Size;
int DataSize;
};
// Declarations
enum struct MacroLocation
{
Unknown,
ClassHead,
ClassBody,
FunctionHead,
FunctionParameters,
FunctionBody,
};
enum struct AccessSpecifier
{
Private,
Protected,
Public
};
struct DeclarationContext;
struct PreprocessedEntity;
struct CS_API Declaration
{
AccessSpecifier Access;
DeclarationContext* _Namespace;
std::string Name;
RawComment* Comment;
std::string DebugText;
bool IsIncomplete;
bool IsDependent;
Declaration* CompleteDeclaration;
unsigned DefinitionOrder;
std::vector<PreprocessedEntity*> PreprocessedEntities;
void* OriginalPtr;
};
struct Class;
struct Enumeration;
struct Function;
struct TypedefDecl;
struct Namespace;
struct Template;
struct Variable;
struct CS_API DeclarationContext : public Declaration
{
Declaration* FindAnonymous(uint64_t key);
CppSharp::CppParser::Namespace* FindNamespace(const std::string& Name);
CppSharp::CppParser::Namespace* FindNamespace(const std::vector<std::string>&);
CppSharp::CppParser::Namespace* FindCreateNamespace(const std::string& Name);
Class* CreateClass(std::string Name, bool IsComplete);
Class* FindClass(const std::string& Name);
Class* FindClass(const std::string& Name, bool IsComplete,
bool Create = false);
Enumeration* FindEnum(const std::string& Name, bool Create = false);
Function* FindFunction(const std::string& Name, bool Create = false);
TypedefDecl* FindTypedef(const std::string& Name, bool Create = false);
std::vector<CppSharp::CppParser::Namespace*> Namespaces;
std::vector<Enumeration*> Enums;
std::vector<Function*> Functions;
std::vector<Class*> Classes;
std::vector<Template*> Templates;
std::vector<TypedefDecl*> Typedefs;
std::vector<Variable*> Variables;
std::map<uint64_t, Declaration*> Anonymous;
};
struct CS_API TypedefDecl : public Declaration
{
QualifiedType QualifiedType;
};
struct CS_API Parameter : public Declaration
{
Parameter() : IsIndirect(false) {}
QualifiedType QualifiedType;
bool IsIndirect;
bool HasDefaultValue;
};
enum struct CXXMethodKind
{
Normal,
Constructor,
Destructor,
Conversion,
Operator,
UsingDirective
};
enum struct CXXOperatorKind
{
None,
New,
Delete,
Array_New,
Array_Delete,
Plus,
Minus,
Star,
Slash,
Percent,
Caret,
Amp,
Pipe,
Tilde,
Exclaim,
Equal,
Less,
Greater,
PlusEqual,
MinusEqual,
StarEqual,
SlashEqual,
PercentEqual,
CaretEqual,
AmpEqual,
PipeEqual,
LessLess,
GreaterGreater,
LessLessEqual,
GreaterGreaterEqual,
EqualEqual,
ExclaimEqual,
LessEqual,
GreaterEqual,
AmpAmp,
PipePipe,
PlusPlus,
MinusMinus,
Comma,
ArrowStar,
Arrow,
Call,
Subscript,
Conditional
};
struct CS_API Function : public Declaration
{
Function() : IsReturnIndirect(false) {}
QualifiedType ReturnType;
bool IsReturnIndirect;
bool IsVariadic;
bool IsInline;
bool IsPure;
CXXOperatorKind OperatorKind;
std::string Mangled;
CallingConvention CallingConvention;
std::vector<Parameter*> Parameters;
};
struct AccessSpecifierDecl;
struct CS_API Method : public Function
{
AccessSpecifierDecl* AccessDecl;
bool IsVirtual;
bool IsStatic;
bool IsConst;
bool IsImplicit;
bool IsOverride;
CXXMethodKind Kind;
bool IsDefaultConstructor;
bool IsCopyConstructor;
bool IsMoveConstructor;
};
struct CS_API Enumeration : public Declaration
{
struct CS_API Item : public Declaration
{
std::string Name;
std::string Expression;
std::string Comment;
uint64_t Value;
};
enum struct CS_FLAGS EnumModifiers
{
Anonymous = 1 << 0,
Scoped = 1 << 1,
Flags = 1 << 2,
};
EnumModifiers Modifiers;
Type* Type;
BuiltinType* BuiltinType;
std::vector<Item> Items;
};
struct CS_API Variable : public Declaration
{
std::string Mangled;
QualifiedType QualifiedType;
};
struct CS_API BaseClassSpecifier
{
AccessSpecifier Access;
bool IsVirtual;
Type* Type;
};
struct Class;
struct CS_API Field : public Declaration
{
QualifiedType QualifiedType;
AccessSpecifier Access;
unsigned Offset;
Class* Class;
};
struct CS_API AccessSpecifierDecl : public Declaration
{
};
struct CS_API Class : public DeclarationContext
{
std::vector<BaseClassSpecifier*> Bases;
std::vector<Field*> Fields;
std::vector<Method*> Methods;
std::vector<AccessSpecifierDecl*> Specifiers;
bool IsPOD;
bool IsAbstract;
bool IsUnion;
bool IsDynamic;
bool IsPolymorphic;
bool HasNonTrivialDefaultConstructor;
bool HasNonTrivialCopyConstructor;
ClassLayout Layout;
};
struct CS_API Template : public Declaration
{
Declaration* TemplatedDecl;
std::vector<TemplateParameter> Parameters;
};
struct CS_API ClassTemplate : public Template
{
};
struct CS_API ClassTemplateSpecialization : public Declaration
{
};
struct CS_API ClassTemplatePartialSpecialization : public Declaration
{
};
struct CS_API FunctionTemplate : public Template
{
};
struct CS_API Namespace : public DeclarationContext
{
};
struct CS_API PreprocessedEntity : public Declaration
{
PreprocessedEntity() : Location(MacroLocation::Unknown) {}
MacroLocation Location;
};
struct CS_API MacroDefinition : public PreprocessedEntity
{
std::string Expression;
};
struct CS_API MacroExpansion : public PreprocessedEntity
{
std::string Text;
MacroDefinition* Definition;
};
struct CS_API TranslationUnit : public Namespace
{
std::string FileName;
bool IsSystemHeader;
std::vector<Namespace*> Namespaces;
std::vector<MacroDefinition*> Macros;
};
struct CS_API NativeLibrary
{
std::string FileName;
std::vector<std::string> Symbols;
};
struct CS_API Library
{
TranslationUnit* FindOrCreateModule(const std::string& File);
NativeLibrary* FindOrCreateLibrary(const std::string& File);
std::vector<TranslationUnit*> TranslationUnits;
std::vector<NativeLibrary*> Libraries;
};
} }

48
src/CppParser/CXXABI.h

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for C++ AST support. Concrete
// subclasses of this implement AST support for specific C++ ABIs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_CXXABI_H
#define LLVM_CLANG_AST_CXXABI_H
#include "clang/AST/Type.h"
namespace clang {
class ASTContext;
class MemberPointerType;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
public:
virtual ~CXXABI();
/// Returns the size of a member pointer in multiples of the target
/// pointer size.
virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv() const = 0;
// Returns whether the given class is nearly empty, with just virtual pointers
// and no data except possibly virtual bases.
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0;
};
/// Creates an instance of a C++ ABI class.
CXXABI *CreateARMCXXABI(ASTContext &Ctx);
CXXABI *CreateItaniumCXXABI(ASTContext &Ctx);
CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx);
}
#endif

283
src/CppParser/Comments.cpp

@ -0,0 +1,283 @@ @@ -0,0 +1,283 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#include "Parser.h"
#include <clang/AST/ASTContext.h>
using namespace CppSharp::CppParser;
//-----------------------------------//
static RawCommentKind
ConvertCommentKind(clang::RawComment::CommentKind Kind)
{
using clang::RawComment;
switch(Kind)
{
case RawComment::RCK_Invalid: return RawCommentKind::Invalid;
case RawComment::RCK_OrdinaryBCPL: return RawCommentKind::OrdinaryBCPL;
case RawComment::RCK_OrdinaryC: return RawCommentKind::OrdinaryC;
case RawComment::RCK_BCPLSlash: return RawCommentKind::BCPLSlash;
case RawComment::RCK_BCPLExcl: return RawCommentKind::BCPLExcl;
case RawComment::RCK_JavaDoc: return RawCommentKind::JavaDoc;
case RawComment::RCK_Qt: return RawCommentKind::Qt;
case RawComment::RCK_Merged: return RawCommentKind::Merged;
}
llvm_unreachable("Unknown comment kind");
}
RawComment* Parser::WalkRawComment(const clang::RawComment* RC)
{
using namespace clang;
auto &SM = C->getSourceManager();
auto Comment = new RawComment();
Comment->Kind = ConvertCommentKind(RC->getKind());
Comment->Text = RC->getRawText(SM);
Comment->BriefText = RC->getBriefText(*AST);
return Comment;
}
#if 0
static InlineCommandComment::RenderKind
ConvertRenderKind(clang::comments::InlineCommandComment::RenderKind Kind)
{
using namespace clang::comments;
switch(Kind)
{
case InlineCommandComment::RenderNormal:
return InlineCommandComment::RenderKind::RenderNormal;
case InlineCommandComment::RenderBold:
return InlineCommandComment::RenderKind::RenderBold;
case InlineCommandComment::RenderMonospaced:
return InlineCommandComment::RenderKind::RenderMonospaced;
case InlineCommandComment::RenderEmphasized:
return InlineCommandComment::RenderKind::RenderEmphasized;
}
llvm_unreachable("Unknown render kind");
}
static ParamCommandComment::PassDirection
ConvertParamPassDirection(clang::comments::ParamCommandComment::PassDirection Dir)
{
using namespace clang::comments;
switch(Dir)
{
case ParamCommandComment::In:
return ParamCommandComment::PassDirection::In;
case ParamCommandComment::Out:
return ParamCommandComment::PassDirection::Out;
case ParamCommandComment::InOut:
return ParamCommandComment::PassDirection::InOut;
}
llvm_unreachable("Unknown parameter pass direction");
}
static void HandleBlockCommand(const clang::comments::BlockCommandComment *CK,
BlockCommandComment^ BC)
{
using namespace clix;
BC->CommandId = CK->getCommandID();
for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
{
auto Arg = BlockCommandComment::Argument();
Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
BC->Arguments->Add(Arg);
}
}
static Comment^ ConvertCommentBlock(clang::comments::Comment* C)
{
using namespace clang;
using clang::comments::Comment;
using namespace clix;
using namespace CppSharp::AST;
// This needs to have an underscore else we get an ICE under VS2012.
Comment^ _Comment;
switch(C->getCommentKind())
{
case Comment::BlockCommandCommentKind:
{
auto CK = cast<const clang::comments::BlockCommandComment>(C);
auto BC = new BlockCommandComment();
_Comment = BC;
HandleBlockCommand(CK, BC);
break;
}
case Comment::ParamCommandCommentKind:
{
auto CK = cast<clang::comments::ParamCommandComment>(C);
auto PC = new ParamCommandComment();
_Comment = PC;
HandleBlockCommand(CK, PC);
PC->Direction = ConvertParamPassDirection(CK->getDirection());
if (CK->isParamIndexValid() && !CK->isVarArgParam())
PC->ParamIndex = CK->getParamIndex();
break;
}
case Comment::TParamCommandCommentKind:
{
auto CK = cast<clang::comments::TParamCommandComment>(C);
_Comment = new TParamCommandComment();
auto TC = new TParamCommandComment();
_Comment = TC;
HandleBlockCommand(CK, TC);
if (CK->isPositionValid())
for (unsigned I = 0, E = CK->getDepth(); I != E; ++I)
TC->Position->Add(CK->getIndex(I));
break;
}
case Comment::VerbatimBlockCommentKind:
{
auto CK = cast<clang::comments::VerbatimBlockComment>(C);
auto VB = new VerbatimBlockComment();
_Comment = VB;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Line = ConvertCommentBlock(*I);
VB->Lines->Add(dynamic_cast<VerbatimBlockLineComment^>(Line));
}
break;
}
case Comment::VerbatimLineCommentKind:
{
auto CK = cast<clang::comments::VerbatimLineComment>(C);
auto VL = new VerbatimLineComment();
_Comment = VL;
VL->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::ParagraphCommentKind:
{
auto CK = cast<clang::comments::ParagraphComment>(C);
auto PC = new ParagraphComment();
_Comment = PC;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Content = ConvertCommentBlock(*I);
PC->Content->Add(dynamic_cast<InlineContentComment^>(Content));
}
PC->IsWhitespace = CK->isWhitespace();
break;
}
case Comment::FullCommentKind:
{
auto CK = cast<clang::comments::FullComment>(C);
auto FC = new FullComment();
_Comment = FC;
for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
{
auto Content = ConvertCommentBlock(*I);
FC->Blocks->Add(dynamic_cast<BlockContentComment^>(Content));
}
break;
}
case Comment::HTMLStartTagCommentKind:
{
auto CK = cast<clang::comments::HTMLStartTagComment>(C);
auto TC = new HTMLStartTagComment();
_Comment = TC;
TC->TagName = marshalString<E_UTF8>(CK->getTagName());
for (unsigned I = 0, E = CK->getNumAttrs(); I != E; ++I)
{
auto A = CK->getAttr(I);
auto Attr = HTMLStartTagComment::Attribute();
Attr.Name = marshalString<E_UTF8>(A.Name);
Attr.Value = marshalString<E_UTF8>(A.Value);
TC->Attributes->Add(Attr);
}
break;
}
case Comment::HTMLEndTagCommentKind:
{
auto CK = cast<clang::comments::HTMLEndTagComment>(C);
auto TC = new HTMLEndTagComment();
_Comment = TC;
TC->TagName = marshalString<E_UTF8>(CK->getTagName());
break;
}
case Comment::TextCommentKind:
{
auto CK = cast<clang::comments::TextComment>(C);
auto TC = new TextComment();
_Comment = TC;
TC->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::InlineCommandCommentKind:
{
auto CK = cast<clang::comments::InlineCommandComment>(C);
auto IC = new InlineCommandComment();
_Comment = IC;
IC->Kind = ConvertRenderKind(CK->getRenderKind());
for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
{
auto Arg = InlineCommandComment::Argument();
Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
IC->Arguments->Add(Arg);
}
break;
}
case Comment::VerbatimBlockLineCommentKind:
{
auto CK = cast<clang::comments::VerbatimBlockLineComment>(C);
auto VL = new VerbatimBlockLineComment();
_Comment = VL;
VL->Text = marshalString<E_UTF8>(CK->getText());
break;
}
case Comment::NoCommentKind: return nullptr;
default:
llvm_unreachable("Unknown comment kind");
}
assert(_Comment && "Invalid comment instance");
return _Comment;
}
#endif
void Parser::HandleComments(clang::Decl* D, Declaration* Decl)
{
using namespace clang;
using namespace clang::comments;
const clang::RawComment* RC = 0;
if (!(RC = AST->getRawCommentForAnyRedecl(D)))
return;
auto RawComment = WalkRawComment(RC);
Decl->Comment = RawComment;
#if 0
if (FullComment* FC = RC->parse(*AST, &C->getPreprocessor(), D))
{
auto CB = static_cast<FullComment^>(ConvertCommentBlock(FC));
RawComment->FullComment = CB;
}
#endif
// Debug Text
SourceManager& SM = C->getSourceManager();
const LangOptions& LangOpts = C->getLangOpts();
auto Range = CharSourceRange::getTokenRange(D->getSourceRange());
bool Invalid;
StringRef DeclText = Lexer::getSourceText(Range, SM, LangOpts, &Invalid);
//assert(!Invalid && "Should have a valid location");
if (!Invalid)
Decl->DebugText = DeclText;
}

94
src/CppParser/CppParser.h

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#pragma once
#include "AST.h"
namespace CppSharp { namespace CppParser {
struct CS_API ParserOptions
{
ParserOptions()
{
MicrosoftMode = false;
NoStandardIncludes = false;
NoBuiltinIncludes = false;
}
// Include directories
std::vector<std::string> IncludeDirs;
std::vector<std::string> SystemIncludeDirs;
std::vector<std::string> Defines;
std::vector<std::string> LibraryDirs;
// C/C++ header file name.
std::string FileName;
Library* Library;
int ToolSetToUse;
std::string TargetTriple;
bool NoStandardIncludes;
bool NoBuiltinIncludes;
bool MicrosoftMode;
CppAbi Abi;
bool Verbose;
};
enum struct ParserDiagnosticLevel
{
Ignored,
Note,
Warning,
Error,
Fatal
};
struct CS_API ParserDiagnostic
{
std::string FileName;
std::string Message;
ParserDiagnosticLevel Level;
int LineNumber;
int ColumnNumber;
};
enum struct ParserResultKind
{
Success,
Error,
FileNotFound
};
struct CS_API ParserResult
{
ParserResultKind Kind;
Library* Library;
std::vector<ParserDiagnostic> Diagnostics;
};
enum class SourceLocationKind
{
Invalid,
Builtin,
CommandLine,
System,
User
};
class CS_API ClangParser
{
public:
static ParserResult* ParseHeader(ParserOptions* Opts);
static ParserResult* ParseLibrary(ParserOptions* Opts);
};
} }

2370
src/CppParser/Parser.cpp

File diff suppressed because it is too large Load Diff

118
src/CppParser/Parser.h

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#pragma once
#include <llvm/Support/Host.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/ASTConsumers.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/TargetOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/IdentifierTable.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/RawCommentList.h>
#include <clang/AST/Comment.h>
#include <clang/AST/RecordLayout.h>
#include <clang/AST/VTableBuilder.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessingRecord.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Sema/Sema.h>
#include "CXXABI.h"
#include "CppParser.h"
#include <string>
typedef std::string String;
namespace clang {
class TargetCodeGenInfo;
namespace CodeGen {
class CodeGenTypes;
}
}
#define Debug printf
namespace CppSharp { namespace CppParser {
struct Parser
{
Parser(ParserOptions* Opts);
void SetupHeader();
ParserResult* ParseHeader(const std::string& File);
ParserResult* ParseLibrary(const std::string& File);
ParserResultKind ParseArchive(llvm::StringRef File,
llvm::MemoryBuffer *Buffer);
ParserResultKind ParseSharedLib(llvm::StringRef File,
llvm::MemoryBuffer *Buffer);
protected:
// AST traversers
void WalkAST();
void WalkMacros(clang::PreprocessingRecord* PR);
Declaration* WalkDeclaration(clang::Decl* D,
bool IgnoreSystemDecls = true, bool CanBeDefinition = false);
Declaration* WalkDeclarationDef(clang::Decl* D);
Enumeration* WalkEnum(clang::EnumDecl*);
Function* WalkFunction(clang::FunctionDecl*, bool IsDependent = false,
bool AddToNamespace = true);
Class* WalkRecordCXX(clang::CXXRecordDecl*);
Method* WalkMethodCXX(clang::CXXMethodDecl*);
Field* WalkFieldCXX(clang::FieldDecl*, Class*);
ClassTemplate* Parser::WalkClassTemplate(clang::ClassTemplateDecl*);
FunctionTemplate* Parser::WalkFunctionTemplate(
clang::FunctionTemplateDecl*);
Variable* WalkVariable(clang::VarDecl*);
RawComment* WalkRawComment(const clang::RawComment*);
Type* WalkType(clang::QualType, clang::TypeLoc* = 0,
bool DesugarType = false);
void WalkVTable(clang::CXXRecordDecl*, Class*);
VTableLayout WalkVTableLayout(const clang::VTableLayout&);
VTableComponent WalkVTableComponent(const clang::VTableComponent&);
// Clang helpers
SourceLocationKind GetLocationKind(const clang::SourceLocation& Loc);
bool IsValidDeclaration(const clang::SourceLocation& Loc);
std::string GetDeclMangledName(clang::Decl*, clang::TargetCXXABI,
bool IsDependent = false);
std::string GetTypeName(const clang::Type*);
void HandleComments(clang::Decl* D, Declaration*);
void WalkFunction(clang::FunctionDecl* FD, Function* F,
bool IsDependent = false);
void HandlePreprocessedEntities(Declaration* Decl, clang::SourceRange sourceRange,
MacroLocation macroLocation = MacroLocation::Unknown);
bool GetDeclText(clang::SourceRange, std::string& Text);
TranslationUnit* GetTranslationUnit(clang::SourceLocation Loc,
SourceLocationKind *Kind = 0);
TranslationUnit* GetTranslationUnit(const clang::Decl*);
DeclarationContext* GetNamespace(clang::Decl*, clang::DeclContext*);
DeclarationContext* GetNamespace(clang::Decl*);
clang::CallingConv GetAbiCallConv(clang::CallingConv CC,
bool IsInstMethod, bool IsVariadic);
void HandleDiagnostics(ParserResult* res);
int Index;
Library* Lib;
ParserOptions* Opts;
llvm::OwningPtr<clang::CompilerInstance> C;
clang::ASTContext* AST;
clang::TargetCXXABI::Kind TargetABI;
clang::TargetCodeGenInfo* CodeGenInfo;
clang::CodeGen::CodeGenTypes* CodeGenTypes;
};
} }

257
src/CppParser/VSLookup.cpp

@ -0,0 +1,257 @@ @@ -0,0 +1,257 @@
/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/
#ifdef _MSC_VER
#include <string>
#include <vector>
#include <cctype>
// Include the necessary headers to interface with the Windows registry and
// environment.
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOMINMAX
#include <Windows.h>
/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numeric
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
char *value, size_t maxLength) {
HKEY hRootKey = NULL;
HKEY hKey = NULL;
const char* subKey = NULL;
DWORD valueType;
DWORD valueSize = maxLength - 1;
long lResult;
bool returnValue = false;
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
hRootKey = HKEY_CLASSES_ROOT;
subKey = keyPath + 18;
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
hRootKey = HKEY_USERS;
subKey = keyPath + 11;
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
hRootKey = HKEY_LOCAL_MACHINE;
subKey = keyPath + 19;
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
hRootKey = HKEY_CURRENT_USER;
subKey = keyPath + 18;
} else {
return false;
}
const char *placeHolder = strstr(subKey, "$VERSION");
char bestName[256];
bestName[0] = '\0';
// If we have a $VERSION placeholder, do the highest-version search.
if (placeHolder) {
const char *keyEnd = placeHolder - 1;
const char *nextKey = placeHolder;
// Find end of previous key.
while ((keyEnd > subKey) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - subKey;
char partialKey[256];
if (partialKeyLength > sizeof(partialKey))
partialKeyLength = sizeof(partialKey);
strncpy(partialKey, subKey, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
int bestIndex = -1;
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
const char *sp = keyName;
while (*sp && !isdigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
while (*ep && (isdigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
double value = strtod(numBuf, NULL);
// Check if InstallDir key value exists.
bool isViableVersion = false;
lResult = RegOpenKeyExA(hTopKey, keyName, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, NULL, NULL, NULL);
if (lResult == ERROR_SUCCESS)
isViableVersion = true;
RegCloseKey(hKey);
}
if (isViableVersion && (value > bestValue)) {
bestIndex = (int)index;
bestValue = value;
strcpy(bestName, keyName);
goto Out;
}
size = sizeof(keyName) - 1;
}
Out:
// If we found the highest versioned key, open the key and get the value.
if (bestIndex != -1) {
// Append rest of key.
strncat(bestName, nextKey, sizeof(bestName) - 1);
bestName[sizeof(bestName) - 1] = '\0';
// Open the chosen key path remainder.
lResult = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
RegCloseKey(hTopKey);
}
} else {
lResult = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
return returnValue;
}
/// \brief Get Windows SDK installation directory.
static bool getWindowsSDKDir(std::string &path) {
char windowsSDKInstallDir[256];
// Try the Windows registry.
bool hasSDKDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder",
windowsSDKInstallDir,
sizeof(windowsSDKInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasSDKDir && windowsSDKInstallDir[0]) {
path = windowsSDKInstallDir;
return true;
}
return false;
}
// Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
// First check the environment variables that vsvars32.bat sets.
const char* vcinstalldir = getenv("VCINSTALLDIR");
if (vcinstalldir) {
char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
if (p)
*p = '\0';
path = vcinstalldir;
return true;
}
char vsIDEInstallDir[256];
char vsExpressIDEInstallDir[256];
// Then try the windows registry.
bool hasVCDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
"InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
bool hasVCExpressDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
"InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsIDEInstallDir;
return true;
}
if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsExpressIDEInstallDir;
return true;
}
// Try the environment.
const char *vs100comntools = getenv("VS100COMNTOOLS");
const char *vs90comntools = getenv("VS90COMNTOOLS");
const char *vs80comntools = getenv("VS80COMNTOOLS");
const char *vscomntools = NULL;
// Try to find the version that we were compiled with
if(false) {}
#if (_MSC_VER >= 1600) // VC100
else if(vs100comntools) {
vscomntools = vs100comntools;
}
#elif (_MSC_VER == 1500) // VC80
else if(vs90comntools) {
vscomntools = vs90comntools;
}
#elif (_MSC_VER == 1400) // VC80
else if(vs80comntools) {
vscomntools = vs80comntools;
}
#endif
// Otherwise find any version we can
else if (vs100comntools)
vscomntools = vs100comntools;
else if (vs90comntools)
vscomntools = vs90comntools;
else if (vs80comntools)
vscomntools = vs80comntools;
if (vscomntools && *vscomntools) {
const char *p = strstr(vscomntools, "\\Common7\\Tools");
path = p ? std::string(vscomntools, p) : vscomntools;
return true;
}
return false;
}
std::vector<std::string> GetWindowsSystemIncludeDirs() {
std::vector<std::string> Paths;
std::string VSDir;
std::string WindowsSDKDir;
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioDir(VSDir)) {
Paths.push_back(VSDir + "\\VC\\include");
if (getWindowsSDKDir(WindowsSDKDir))
Paths.push_back(WindowsSDKDir + "\\include");
else
Paths.push_back(VSDir + "\\VC\\PlatformSDK\\Include");
}
return Paths;
}
#endif

88
src/CppParser/premake4.lua

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
clang_msvc_flags =
{
"/wd4146", "/wd4244", "/wd4800", "/wd4345",
"/wd4355", "/wd4996", "/wd4624", "/wd4291",
"/wd4251"
}
project "CppSharp.CppParser"
kind "SharedLib"
language "C++"
SetupNativeProject()
flags { common_flags }
configuration "vs*"
buildoptions { clang_msvc_flags }
files { "VSLookup.cpp" }
configuration "*"
files
{
"*.h",
"*.cpp",
"*.lua"
}
includedirs
{
"../../deps/LLVM/include",
"../../deps/LLVM/build/include",
"../../deps/LLVM/tools/clang/include",
"../../deps/LLVM/tools/clang/lib",
"../../deps/LLVM/build/tools/clang/include"
}
configuration "Debug"
libdirs { "../../deps/LLVM/build/lib/Debug" }
configuration "Release"
libdirs { "../../deps/LLVM/build/lib/RelWithDebInfo" }
configuration "*"
links
{
"clangAnalysis",
"clangAST",
"clangBasic",
"clangCodeGen",
"clangDriver",
"clangEdit",
"clangFrontend",
"clangLex",
"clangParse",
"clangSema",
"clangSerialization",
"LLVMAnalysis",
"LLVMAsmParser",
"LLVMBitReader",
"LLVMBitWriter",
"LLVMCodeGen",
"LLVMCore",
"LLVMipa",
"LLVMipo",
"LLVMInstCombine",
"LLVMInstrumentation",
"LLVMIRReader",
"LLVMLinker",
"LLVMMC",
"LLVMMCParser",
"LLVMObjCARCOpts",
"LLVMObject",
"LLVMOption",
"LLVMScalarOpts",
"LLVMSupport",
"LLVMTarget",
"LLVMTransformUtils",
"LLVMVectorize",
"LLVMX86AsmParser",
"LLVMX86AsmPrinter",
"LLVMX86Desc",
"LLVMX86Info",
"LLVMX86Utils",
}
include ("Bindings")
Loading…
Cancel
Save