Skip to content

Commit

Permalink
feat: add support for bitfields
Browse files Browse the repository at this point in the history
closes #212
  • Loading branch information
sdkrystian committed Jun 30, 2023
1 parent 9798204 commit 8c82517
Show file tree
Hide file tree
Showing 17 changed files with 343 additions and 40 deletions.
1 change: 1 addition & 0 deletions include/mrdox/Metadata.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// metadata extracted from AST

#include <mrdox/Metadata/Enum.hpp>
#include <mrdox/Metadata/Expression.hpp>
#include <mrdox/Metadata/Field.hpp>
#include <mrdox/Metadata/Function.hpp>
#include <mrdox/Metadata/Info.hpp>
Expand Down
51 changes: 51 additions & 0 deletions include/mrdox/Metadata/Expression.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (c) 2023 Krystian Stasiowski ([email protected])
//
// Official repository: https://github.com/cppalliance/mrdox
//

#ifndef MRDOX_API_METADATA_EXPRESSION_HPP
#define MRDOX_API_METADATA_EXPRESSION_HPP

#include <mrdox/Platform.hpp>
#include <concepts>
#include <optional>
#include <string>

namespace clang {
namespace mrdox {

/** Represents an expression */
struct ExprInfo
{
/** The expression, as written */
std::string Written;
};

/** Represents an expression with a (possibly known) value */
template<typename T>
struct ConstantExprInfo
: ExprInfo
{
/** The underlying type of the expression */
using type = T;

/** The expressions value, if it is known
The value of an expression will be unknown
if it is e.g. dependent on a template parameter
*/
std::optional<type> Value;

static_assert(std::integral<type>,
"expression type must be integral");
};

} // clang
} // mrdox

#endif
7 changes: 7 additions & 0 deletions include/mrdox/Metadata/Field.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define MRDOX_API_METADATA_FIELD_HPP

#include <mrdox/Platform.hpp>
#include <mrdox/Metadata/Expression.hpp>
#include <mrdox/Metadata/Info.hpp>
#include <mrdox/Metadata/Source.hpp>
#include <mrdox/Metadata/Type.hpp>
Expand Down Expand Up @@ -55,6 +56,12 @@ struct FieldInfo
/** Whether the field is declared mutable */
bool IsMutable = false;

/** Whether the field is a bitfield */
bool IsBitfield = false;

/** The width of the bitfield */
ConstantExprInfo<std::uint64_t> BitfieldWidth;

//--------------------------------------------

explicit
Expand Down
4 changes: 4 additions & 0 deletions include/mrdox/MetadataFwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ struct TypedefInfo;
struct VariableInfo;
struct VerbatimBlock;

struct ExprInfo;
template<typename T>
struct ConstantExprInfo;

struct TemplateInfo;
struct TArg;
struct TParam;
Expand Down
3 changes: 2 additions & 1 deletion mrdox.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,12 @@ grammar
#---------------------------------------------

Field =
element field
element (field|bitfield)
{
Name,
Access ?,
ID,
attribute width { text } ?,
attribute default { text } ?,
Location,
(
Expand Down
1 change: 1 addition & 0 deletions source/-XML/CXXTags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ constexpr llvm::StringRef accessTagName = "access";
constexpr llvm::StringRef aliasTagName = "alias";
constexpr llvm::StringRef attributeTagName = "attr";
constexpr llvm::StringRef baseTagName = "base";
constexpr llvm::StringRef bitfieldTagName = "bitfield";
constexpr llvm::StringRef classTagName = "class";
constexpr llvm::StringRef dataMemberTagName = "field";
constexpr llvm::StringRef javadocTagName = "doc";
Expand Down
15 changes: 13 additions & 2 deletions source/-XML/XMLWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,21 @@ XMLWriter::
writeField(
const FieldInfo& I)
{
tags_.open(dataMemberTagName, {
std::string_view tag_name = dataMemberTagName;
std::string bit_width;
if(I.IsBitfield)
{
tag_name = bitfieldTagName;
bit_width = I.BitfieldWidth.Value ?
std::to_string(*I.BitfieldWidth.Value) :
I.BitfieldWidth.Written;
}

tags_.open(tag_name, {
{ "name", I.Name },
{ I.Access },
{ I.id },
{ "width", bit_width, I.IsBitfield },
{ "default", I.Default, ! I.Default.empty() }
});

Expand All @@ -397,7 +408,7 @@ writeField(

writeJavadoc(I.javadoc);

tags_.close(dataMemberTagName);
tags_.close(tag_name);
}

void
Expand Down
38 changes: 38 additions & 0 deletions source/AST/ASTVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,36 @@ buildTypeInfoForType(
}
}

void
ASTVisitor::
buildExprInfoForExpr(
ExprInfo& I,
const Expr* E)
{
I.Written = getSourceCode(
E->getSourceRange());
}

template<typename T>
void
ASTVisitor::
buildExprInfoForExpr(
ConstantExprInfo<T>& I,
const Expr* E)
{
buildExprInfoForExpr(
static_cast<ExprInfo&>(I), E);
// if the expression is dependent,
// we cannot get its value
if(E->isValueDependent())
return;
llvm::APSInt value = E->EvaluateKnownConstInt(*astContext_);
if constexpr(std::is_signed_v<T>)
I.Value.emplace(value.getSExtValue());
else
I.Value.emplace(value.getZExtValue());
}

void
ASTVisitor::
parseParameters(
Expand Down Expand Up @@ -1277,6 +1307,14 @@ buildField(

I.IsMutable = D->isMutable();

if(D->isBitField())
{
I.IsBitfield = true;
buildExprInfoForExpr(
I.BitfieldWidth,
D->getBitWidth());
}

I.specs.hasNoUniqueAddress = D->hasAttr<NoUniqueAddressAttr>();
I.specs.isDeprecated = D->hasAttr<DeprecatedAttr>();
I.specs.isMaybeUnused = D->hasAttr<UnusedAttr>();
Expand Down
11 changes: 11 additions & 0 deletions source/AST/ASTVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ class ASTVisitor
buildTypeInfoForType(
QualType T);

void
buildExprInfoForExpr(
ExprInfo& I,
const Expr* E);

template<typename T>
void
buildExprInfoForExpr(
ConstantExprInfo<T>& I,
const Expr* E);

void
parseParameters(
FunctionInfo& I,
Expand Down
72 changes: 72 additions & 0 deletions source/AST/AnyBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,71 @@ class SourceInfoBlock

//------------------------------------------------

class ExprBlock
: public BitcodeReader::AnyBlock
{
private:

protected:
BitcodeReader& br_;
ExprInfo& I_;
void(*on_value)(
ExprInfo&,
std::uint64_t) = nullptr;

public:
ExprBlock(
ExprInfo& I,
BitcodeReader& br) noexcept
: br_(br)
, I_(I)
{
}

template<typename T>
ExprBlock(
ConstantExprInfo<T>& I,
BitcodeReader& br) noexcept
: br_(br)
, I_(I)
, on_value([](
ExprInfo& expr, std::uint64_t val)
{
static_cast<ConstantExprInfo<T>&>(
expr).Value.emplace(val);
})
{
}

Error
parseRecord(
Record const& R,
unsigned ID,
llvm::StringRef Blob) override
{
switch(ID)
{
case EXPR_WRITTEN:
return decodeRecord(R, I_.Written, Blob);
case EXPR_VALUE:
{
if(! on_value)
return Error("EXPR_VALUE for expression without value");
std::uint64_t value = 0;
if(auto err = decodeRecord(R, value, Blob))
return err;
on_value(I_, value);
return Error::success();

}
default:
return AnyBlock::parseRecord(R, ID, Blob);
}
}
};

//------------------------------------------------

class TypeInfoBlock
: public BitcodeReader::AnyBlock
{
Expand Down Expand Up @@ -1253,6 +1318,8 @@ class FieldBlock
return decodeRecord(R, {&I->specs.raw}, Blob);
case FIELD_IS_MUTABLE:
return decodeRecord(R, I->IsMutable, Blob);
case FIELD_IS_BITFIELD:
return decodeRecord(R, I->IsBitfield, Blob);
default:
return TopLevelBlock::parseRecord(R, ID, Blob);
}
Expand All @@ -1269,6 +1336,11 @@ class FieldBlock
TypeInfoBlock B(I->Type, br_);
return br_.readBlock(B, ID);
}
case BI_EXPR_BLOCK_ID:
{
ExprBlock B(I->BitfieldWidth, br_);
return br_.readBlock(B, ID);
}
default:
return TopLevelBlock::readSubBlock(ID);
}
Expand Down
4 changes: 4 additions & 0 deletions source/AST/BitcodeIDs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ enum BlockID
BI_BASE_BLOCK_ID,
BI_ENUM_BLOCK_ID,
BI_ENUM_VALUE_BLOCK_ID,
BI_EXPR_BLOCK_ID,
BI_FIELD_BLOCK_ID,
BI_FUNCTION_BLOCK_ID,
BI_FUNCTION_PARAM_BLOCK_ID,
Expand Down Expand Up @@ -105,6 +106,7 @@ enum RecordID
FIELD_ATTRIBUTES,
FIELD_DEFAULT,
FIELD_IS_MUTABLE,
FIELD_IS_BITFIELD,
FUNCTION_BITS,
FUNCTION_PARAM_NAME,
FUNCTION_PARAM_DEFAULT,
Expand All @@ -118,6 +120,8 @@ enum RecordID
ENUM_VALUE_NAME,
ENUM_VALUE_VALUE,
ENUM_VALUE_EXPR,
EXPR_WRITTEN,
EXPR_VALUE,
RECORD_BITS,
RECORD_FRIENDS,
RECORD_IS_TYPE_DEF,
Expand Down
Loading

0 comments on commit 8c82517

Please sign in to comment.