mirror of https://github.com/mono/CppSharp.git
Browse Source
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
9 changed files with 4117 additions and 0 deletions
@ -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; |
||||
} |
||||
|
||||
} } |
@ -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; |
||||
}; |
||||
|
||||
} } |
@ -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 |
@ -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; |
||||
} |
@ -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); |
||||
}; |
||||
|
||||
} } |
@ -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; |
||||
}; |
||||
|
||||
} } |
@ -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 |
@ -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…
Reference in new issue