Skip to content

Commit

Permalink
[v0.0.5] Another hotfix version to stabilize behaviour in project.
Browse files Browse the repository at this point in the history
Fixed bug with wrong type name in TypeStatement.
Removed Utils::getNormalizedTypeRef function because it's local & buggy place (Replaced by getQualTypeBaseInfo).
Added glm as test project dependency (used to test analyzer).
Added tests for python integration.
Changed type hints in debugger.
  • Loading branch information
DronCode committed Apr 7, 2024
1 parent f034c21 commit 2a7dfae
Show file tree
Hide file tree
Showing 11 changed files with 494 additions and 16 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "ThirdParty/fmt"]
path = ThirdParty/fmt
url = https://github.com/fmtlib/fmt
[submodule "Tests/Unit/test_headers/ThirdParty/glm"]
path = Tests/Unit/test_headers/ThirdParty/glm
url = https://github.com/g-truc/glm
11 changes: 10 additions & 1 deletion LLVM/include/RG3/LLVM/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@

namespace rg3::llvm
{
struct TypeBaseInfo
{
cpp::TypeKind eKind;
std::string sName;
std::string sPrettyName;
cpp::CppNamespace sNameSpace;
cpp::DefinitionLocation sDefLocation;
};

struct Utils
{
static void getDeclInfo(const clang::Decl* decl, rg3::cpp::CppNamespace& nameSpace);
Expand All @@ -19,7 +28,7 @@ namespace rg3::llvm

static cpp::ClassEntryVisibility getDeclVisibilityLevel(const clang::Decl* decl);

static std::string getNormalizedTypeRef(const std::string& typeName);
static bool getQualTypeBaseInfo(const clang::QualType& qualType, TypeBaseInfo& baseInfo, const clang::ASTContext& astContext);

static void fillTypeStatementFromQualType(rg3::cpp::TypeStatement& typeStatement, clang::QualType qt, const clang::ASTContext& astContext);

Expand Down
163 changes: 153 additions & 10 deletions LLVM/source/Utils.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#include <RG3/LLVM/Utils.h>
#include <RG3/LLVM/Visitors/CxxTemplateSpecializationVisitor.h>
#include <RG3/LLVM/Visitors/CxxClassTypeVisitor.h>
#include <RG3/LLVM/Visitors/CxxTypeVisitor.h>
#include <clang/Basic/SourceManager.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/Decl.h>
#include <llvm/Support/Casting.h>
#include <filesystem>
#include <fmt/format.h>


namespace rg3::llvm
Expand Down Expand Up @@ -84,34 +88,173 @@ namespace rg3::llvm
return cpp::ClassEntryVisibility::CEV_PRIVATE;
}

std::string Utils::getNormalizedTypeRef(const std::string& typeName)
bool Utils::getQualTypeBaseInfo(const clang::QualType& qualType, TypeBaseInfo& baseInfo, const clang::ASTContext& astContext)
{
// Here stored known cases when we need to replace one type to another
static const std::unordered_map<std::string, std::string> s_Replacement {
{ "_Bool", "bool" }
};
if (qualType->isTypedefNameType()) // must be first!
{
// Alias. Just use alias name & location data
if (auto* pAsAliasType = qualType->getAs<clang::TypedefType>())
{
if (auto* pAsAliasDecl = pAsAliasType->getDecl())
{
// Detect name
clang::PrintingPolicy typeNamePrintingPolicy { astContext.getLangOpts() };
typeNamePrintingPolicy.SuppressTagKeyword = true;
typeNamePrintingPolicy.SuppressScope = false;
typeNamePrintingPolicy.Bool = true;

// Detect namespace
Utils::getDeclInfo(pAsAliasDecl, baseInfo.sNameSpace);

// Collect definition location
baseInfo.sDefLocation = Utils::getDeclDefinitionInfo(pAsAliasDecl);

// Store info
baseInfo.sName = qualType.getAsString(typeNamePrintingPolicy);
baseInfo.sPrettyName = baseInfo.sNameSpace.isEmpty() ? baseInfo.sName : fmt::format("{}::{}", baseInfo.sNameSpace.asString(), baseInfo.sName);

// Detect kind
if (qualType->isRecordType())
{
baseInfo.eKind = cpp::TypeKind::TK_STRUCT_OR_CLASS;
}
else if (qualType->isEnumeralType() || qualType->isScopedEnumeralType())
{
baseInfo.eKind = cpp::TypeKind::TK_ENUM;
}
else
{
baseInfo.eKind = cpp::TypeKind::TK_TRIVIAL;
}

return true;
}
}

if (auto it = s_Replacement.find(typeName); it != s_Replacement.end())
return false;
}

if (qualType->isRecordType())
{
return it->second;
// No need to support full type analysis pipeline here. Just lookup as 'generic record' and trying to extract type
if (auto* pAsRecord = qualType->getAsRecordDecl())
{
// Collect valid name
clang::PrintingPolicy typeNamePrintingPolicy { astContext.getLangOpts() };
typeNamePrintingPolicy.SuppressTagKeyword = true;
typeNamePrintingPolicy.SuppressScope = true;
typeNamePrintingPolicy.Bool = true;

const auto correctedName = qualType.getUnqualifiedType().getAsString(typeNamePrintingPolicy);

// Collect namespace
Utils::getDeclInfo(pAsRecord, baseInfo.sNameSpace);

// Collect definition location
cpp::DefinitionLocation aDefLocation = Utils::getDeclDefinitionInfo(pAsRecord);

// Save info
baseInfo.sName = correctedName;
baseInfo.sNameSpace = baseInfo.sNameSpace;
baseInfo.sPrettyName = baseInfo.sNameSpace.isEmpty() ? correctedName : fmt::format("{}::{}", baseInfo.sNameSpace.asString(), correctedName);
baseInfo.sDefLocation = aDefLocation;
return true;
}

return false;
}

return typeName;
if (qualType->isEnumeralType() || qualType->isScopedEnumeralType())
{
// C/C++ enum
if (auto* pAsEnumType = qualType->getAs<clang::EnumType>())
{
if (auto* pAsEnumDecl = pAsEnumType->getDecl())
{
CompilerConfig cc {};
cc.bAllowCollectNonRuntimeTypes = true;

std::vector<rg3::cpp::TypeBasePtr> vCollected {};

visitors::CxxTypeVisitor visitor { vCollected, cc };
visitor.TraverseDecl(pAsEnumDecl);

if (!vCollected.empty() && vCollected[0]->getKind() == cpp::TypeKind::TK_ENUM && !vCollected[0]->getPrettyName().empty())
{
baseInfo.eKind = cpp::TypeKind::TK_ENUM;
baseInfo.sName = vCollected[0]->getName();
baseInfo.sNameSpace = vCollected[0]->getNamespace();
baseInfo.sPrettyName = vCollected[0]->getPrettyName();
baseInfo.sDefLocation = vCollected[0]->getDefinition();

return true;
}
}
}

return false;
}

if (qualType->isBuiltinType())
{
// Builtin type (int, float, etc...). Namespace not supported here
if (auto* pAsBuiltinType = qualType->getAs<clang::BuiltinType>())
{
// It's builtin, just register a type
// Our builtins are store as generic rg3::cpp::TypeBase instances
clang::PrintingPolicy typeNamePrintingPolicy { astContext.getLangOpts() };
typeNamePrintingPolicy.SuppressTagKeyword = true;
typeNamePrintingPolicy.SuppressScope = false;
typeNamePrintingPolicy.Bool = true;

baseInfo.eKind = cpp::TypeKind::TK_TRIVIAL;
baseInfo.sName = baseInfo.sPrettyName = pAsBuiltinType->getNameAsCString(typeNamePrintingPolicy);
baseInfo.sNameSpace = {};
baseInfo.sDefLocation = {};
return true;
}
}

// Not supported yet
return false;
}

void Utils::fillTypeStatementFromQualType(rg3::cpp::TypeStatement& typeStatement, clang::QualType qt, const clang::ASTContext& astContext)
{
const clang::SourceManager& sm = astContext.getSourceManager();

typeStatement.sTypeRef = cpp::TypeReference(rg3::llvm::Utils::getNormalizedTypeRef(qt.getAsString()));
{
TypeBaseInfo typeBaseInfo {};
if (!getQualTypeBaseInfo(qt, typeBaseInfo, astContext))
{
// Use "pure" view
typeStatement.sTypeRef = cpp::TypeReference(qt.getUnqualifiedType().getAsString());
}
else
{
// Use correct view
typeStatement.sTypeRef = cpp::TypeReference(typeBaseInfo.sPrettyName);
}
}

typeStatement.bIsConst = qt.isConstQualified();

if (qt->isPointerType() || qt->isReferenceType())
{
TypeBaseInfo typeBaseInfo {};
if (!getQualTypeBaseInfo(qt->getPointeeType().getUnqualifiedType(), typeBaseInfo, astContext))
{
// Use "pure" view
typeStatement.sTypeRef = cpp::TypeReference(qt->getPointeeType().getUnqualifiedType().getAsString());
}
else
{
// Use correct view
typeStatement.sTypeRef = cpp::TypeReference(typeBaseInfo.sPrettyName);
}

typeStatement.bIsPointer = qt->isPointerType();
typeStatement.bIsReference = qt->isReferenceType();
typeStatement.sTypeRef = cpp::TypeReference(rg3::llvm::Utils::getNormalizedTypeRef(qt->getPointeeType().getUnqualifiedType().getAsString()));
typeStatement.bIsPtrConst = qt->getPointeeType().isConstQualified();
}

Expand Down
2 changes: 1 addition & 1 deletion LLVM/source/Visitors/CxxClassTypeVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ namespace rg3::llvm::visitors
cpp::ClassProperty& newProperty = foundProperties.emplace_back();
newProperty.sAlias = newProperty.sName = cxxFieldDecl->getNameAsString();

// Fill type info (and decl info)
// Collect common info
fillTypeStatementFromLLVMEntry(newProperty.sTypeInfo, cxxFieldDecl);

// Save other info
Expand Down
4 changes: 4 additions & 0 deletions LLVM/source/Visitors/CxxRouterVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ namespace rg3::llvm::visitors

// Type is handled here
const size_t iKnownTypes = m_vFoundTypes.size();

// In my case pAsTypedefDecl contains correct pointer in glm case, but... it's weird. Anyway I'm unable to deconstruct this inside that func
bHandled = handleAnnotationBasedType(pInnerType, annotation, ctx, false);

// Ok, last inserted type is our new type (?)
Expand Down Expand Up @@ -485,6 +487,7 @@ namespace rg3::llvm::visitors
ExtraFunctionsFilter functionsFilter { annotation.knownFunctions };
CxxTemplateSpecializationVisitor visitor { newConfig, pTemplateSpecDecl, !annotation.knownProperties.empty(), !annotation.knownFunctions.empty(), propertiesFilter, functionsFilter };

// Here we need to find a correct specialization, but for glm there are no specialization at all...
if (auto* pSpecializedTemplate = pTemplateSpecDecl->getSpecializedTemplate())
{
clang::Decl* pTargetDecl = nullptr;
Expand All @@ -498,6 +501,7 @@ namespace rg3::llvm::visitors
pTargetDecl = classTemplateDecl;
break;
}
// wrong!
}
}

Expand Down
9 changes: 5 additions & 4 deletions PyBind/source/PyTypeBase.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <RG3/PyBind/PyTypeBase.h>
#include <fmt/format.h>


namespace rg3::pybind
Expand All @@ -17,16 +18,16 @@ namespace rg3::pybind
switch (m_base->getKind())
{
case cpp::TypeKind::TK_NONE:
str = "none";
str = "[INVALID TYPE]";
break;
case cpp::TypeKind::TK_TRIVIAL:
str = m_base->getPrettyName();
str = fmt::format("{} [TRIVIAL]", m_base->getPrettyName());
break;
case cpp::TypeKind::TK_ENUM:
str = "enum " + m_base->getPrettyName();
str = fmt::format("{} [ENUM]", m_base->getPrettyName());
break;
case cpp::TypeKind::TK_STRUCT_OR_CLASS:
str = "class " + m_base->getPrettyName();
str = fmt::format("{} [CLASS/STRUCT]", m_base->getPrettyName());
break;
}

Expand Down
Loading

0 comments on commit 2a7dfae

Please sign in to comment.