-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add qualified_name_of #28
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,6 +70,10 @@ static bool name_of(APValue &Result, Sema &S, EvalFn Evaluator, | |
QualType ResultTy, SourceRange Range, | ||
ArrayRef<Expr *> Args); | ||
|
||
static bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, | ||
QualType ResultTy, SourceRange Range, | ||
ArrayRef<Expr *> Args); | ||
|
||
static bool display_name_of(APValue &Result, Sema &S, EvalFn Evaluator, | ||
QualType ResultTy, SourceRange Range, | ||
ArrayRef<Expr *> Args); | ||
|
@@ -326,6 +330,7 @@ static constexpr Metafunction Metafunctions[] = { | |
|
||
// exposed metafunctions | ||
{ Metafunction::MFRK_cstring, 1, 1, name_of }, | ||
{ Metafunction::MFRK_cstring, 1, 1, qualified_name_of }, | ||
{ Metafunction::MFRK_cstring, 1, 1, display_name_of }, | ||
{ Metafunction::MFRK_sourceLoc, 1, 1, source_location_of }, | ||
{ Metafunction::MFRK_metaInfo, 1, 1, type_of }, | ||
|
@@ -1252,6 +1257,66 @@ bool map_decl_to_entity(APValue &Result, Sema &S, EvalFn Evaluator, | |
llvm_unreachable("unknown reflection kind"); | ||
} | ||
|
||
template <typename DT> | ||
bool getQualifiedName(APValue &Result, Sema &S, EvalFn Evaluator, DT& declType) | ||
{ | ||
SmallString<128> QualifiedNameBuffer; | ||
llvm::raw_svector_ostream OS(QualifiedNameBuffer); | ||
declType.printQualifiedName(OS); | ||
StringRef Name = QualifiedNameBuffer.str(); | ||
if( makeCString(Result, Name, S.Context, Evaluator) ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nits for consistency: space after if (makeCString(Result, Name, S.Context, Evaluator)) { |
||
{ | ||
llvm_unreachable("failed to create qualified name string"); | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to |
||
} | ||
return false; | ||
} | ||
|
||
bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, | ||
SourceRange Range, ArrayRef<Expr *> Args) { | ||
assert(Args[0]->getType()->isReflectionType()); | ||
assert(ResultTy == | ||
S.Context.getPointerType(S.Context.getConstType(S.Context.CharTy))); | ||
|
||
APValue R; | ||
if (!Evaluator(R, Args[0], true)) | ||
return true; | ||
|
||
switch (R.getReflection().getKind()) { | ||
case ReflectionValue::RK_type: { | ||
QualType QT = R.getReflectedType(); | ||
return SetAndSucceed(Result, getTypeName(S.Context, Evaluator, QT, | ||
/*emptyIfUnnamed=*/true)); | ||
} | ||
case ReflectionValue::RK_declaration: { | ||
const ValueDecl *VD = cast<ValueDecl>(R.getReflectedDecl()); | ||
return getQualifiedName(Result, S, Evaluator, *VD); | ||
} | ||
case ReflectionValue::RK_template: { | ||
const TemplateDecl *TD = cast<TemplateDecl>(R.getReflectedTemplate().getAsTemplateDecl()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this cast necessary? I think |
||
return getQualifiedName(Result, S, Evaluator, *TD); | ||
} | ||
case ReflectionValue::RK_const_value: { | ||
if (makeCString(Result, "", S.Context, Evaluator)) | ||
llvm_unreachable("failed to create empty string"); | ||
return false; | ||
} | ||
case ReflectionValue::RK_namespace: { | ||
const NamespaceDecl *ND = cast<NamespaceDecl>(R.getReflectedNamespace()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This, surprisingly, actually isn't quite right - in addition to a I think what you'll want to do here is:
We should probably add test cases for |
||
return getQualifiedName(Result, S, Evaluator, *ND); | ||
} | ||
case ReflectionValue::RK_base_specifier: { | ||
QualType QT = R.getReflectedBaseSpecifier()->getType(); | ||
const Decl* D = findTypeDecl(QT); | ||
const TypeDecl *TD = cast<TypeDecl>(D); | ||
return getQualifiedName(Result, S, Evaluator, *TD); | ||
} | ||
case ReflectionValue::RK_data_member_spec: | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although this is what we do for
So that should include this case as well. Let's just stack this case on top of case ReflectionValue::RK_const_value:
case ReflectionValue::RK_data_member_spec: {
if (makeCString(Result, "", S.Context, Evaluator))
llvm_unreachable("failed to create empty string");
return false;
} (bonus points if you want to fix that in |
||
} | ||
llvm_unreachable("unknown reflection kind"); | ||
} | ||
|
||
bool name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, | ||
SourceRange Range, ArrayRef<Expr *> Args) { | ||
assert(Args[0]->getType()->isReflectionType()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include <experimental/meta> | ||
|
||
#include <string> | ||
#include <string_view> | ||
|
||
namespace outer_namespace{ | ||
namespace a_namespace { | ||
namespace an_inner_namespace | ||
{ | ||
struct ClassInsideSomeNamespaces { | ||
int k; | ||
int j; | ||
using type = int; | ||
}; | ||
|
||
typedef ClassInsideSomeNamespaces ClassInsideSomeNamespacesAlias; | ||
|
||
template <typename T> | ||
class SomeTemplateClass | ||
{ | ||
std::vector<T> stuff; | ||
public: | ||
SomeTemplateClass(const T& t) | ||
{ | ||
stuff.push_back(t); | ||
} | ||
}; | ||
|
||
class DerivedClass: public ClassInsideSomeNamespaces | ||
{ | ||
int boopTheBloop; | ||
}; | ||
|
||
const std::string aString = "abcde"; | ||
} // an_inner_namespace | ||
} // a_namespace | ||
} // outer_namespace | ||
|
||
int main() | ||
{ | ||
using namespace outer_namespace; | ||
using namespace a_namespace; | ||
using namespace an_inner_namespace; | ||
|
||
constexpr auto expectedQNofType = "outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespaces"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A few stylistic nits, hope you don't mind:
constexpr auto expectedQNofType = "outer_namespace::a_namespace::"
"an_inner_namespace::ClassInsideSomeNamespaces";
static_assert(expectedQNofDeclaration == qualified_name_of(^aString)); |
||
static_assert(expectedQNofType==std::meta::qualified_name_of(^ClassInsideSomeNamespaces)); | ||
|
||
constexpr auto expectedQNofDeclaration = "outer_namespace::a_namespace::an_inner_namespace::aString"; | ||
static_assert(expectedQNofDeclaration==std::meta::qualified_name_of(^aString)); | ||
|
||
constexpr auto expectedQNofNamespace = "outer_namespace::a_namespace::an_inner_namespace"; | ||
static_assert(expectedQNofNamespace==std::meta::qualified_name_of(^an_inner_namespace)); | ||
|
||
constexpr auto expectedQNofTemplate = "outer_namespace::a_namespace::an_inner_namespace::SomeTemplateClass"; | ||
static_assert(expectedQNofTemplate==std::meta::qualified_name_of(^SomeTemplateClass)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a case to verify that
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. waaaaah! this is broken. I'll take a look... |
||
|
||
constexpr auto expectedQNofTypeAlias = "outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespacesAlias"; | ||
static_assert(expectedQNofTypeAlias==std::meta::qualified_name_of(^ClassInsideSomeNamespacesAlias)); | ||
|
||
constexpr auto expectedQNofDerivedType = "outer_namespace::a_namespace::an_inner_namespace::DerivedClass"; | ||
static_assert(expectedQNofDerivedType==std::meta::qualified_name_of(^DerivedClass)); | ||
|
||
constexpr auto expectedQNofBaseSpecifier="outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespaces"; | ||
constexpr auto base = [:(std::meta::reflect_value(std::meta::bases_of(^DerivedClass)[0])):]; | ||
static_assert(expectedQNofBaseSpecifier==std::meta::qualified_name_of(base)); | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than template-ize this function, we may be able to make
DT& declType
aNamedDecl *
, asNamedDecl
is an ancestor ofValueDecl
,TemplateDecl
,NamespaceDecl
, andTypeDecl
. Passing by reference as you've done here (i.e.,NamedDecl &
) would be just as good, but let's stick with passing by pointer since that's what's done throughout the rest of this file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could but then I have to cast everything which is a bit ugly IMHO. But then I guess it would match the rest of the clang codebase so...