www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reflection to detect public/private/etc?

reply "Nick Sabalausky" <a a.a> writes:
Is there a way to check whether a class member (or other identifier) is 
public, private, protected, package or extern?

Or at least "public/extern" vs "private/protected/package"? (I suspect this 
one may at least be possible with some __traits(compiles, ...) trickery 
(assuming "private" actually works at this point), although I don't know 
whether it would have to take into accout the indentifier's type.)
Aug 12 2011
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
There's no way I've found, aside from direct access (so not via
getMembers) and seeing it it fails to compile.

I started hacking my compiler to add a traits(protection), but
while I got it working on direct symbols, it didn't work on the
stuff returned by __traits(getMember) so it didn't work for me...
it looks like in the compiler, the protection is applied only to
the name, not the stuff it points to.

I really want to get this figured out though so I can drop the
leading underscore from some web.d names...
Aug 12 2011
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:j242up$24so$1 digitalmars.com...
 I really want to get this figured out though so I can drop the
 leading underscore from some web.d names...
Heh, that's exactly what I had in mind ;)
Aug 12 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:j242up$24so$1 digitalmars.com...
 There's no way I've found, aside from direct access (so not via
 getMembers) and seeing it it fails to compile.
I just gave it a try. I think I may be hitting against a bug in __traits(compiles) WRT private. This is the best I could get (Using DMD 2.054, Win): testCheckPrivate2.d: ----------------------------- Foo foo; class Foo { int a; private int b; void c() {} private void d() {} void e(int x) {} private void f(int x) {} } testCheckPrivate.d: ----------------------------- import testCheckPrivate2; template check(string name) { enum check = __traits(compiles, { auto x = &(__traits(getMember, foo, name)); }); } // Any way to do this with foreach? Didn't work when I tried. template checkMembers(members...) { static if(members.length > 0) { // Check the first pragma(msg, members[0] ~ ": " ~ (check!(members[0]) ? "true" : "false") ); // Check the rest static if(members.length > 1) alias checkMembers!(members[1..$]) dummy; } } alias checkMembers!(__traits(allMembers, Foo)) dummy; pragma( msg, "Manually checking foo.d: " ); pragma( msg, __traits(compiles, { auto x = &(foo.d); }) ); void main() { foo.d(); auto x = &(foo.b); auto y = &(foo.d); } Result: ----------------
dmd testCheckPrivate.d testCheckPrivate2.d -c
a: true b: false c: true d: true e: true f: true toString: true toHash: true opCmp: true opEquals: false Monitor: false factory: true Manually checking foo.d: true testCheckPrivate.d(33): Error: class testCheckPrivate2.Foo member d is not accessible testCheckPrivate.d(34): Error: class testCheckPrivate2.Foo member b is not accessible Note that "auto y = &(foo.d);" fails to compile as expected, but __traits(compiles) claims that should compile. It works for the non-function members though. I did the "auto x = &(...);" trick so I wouldn't have to deal with the function's params. Maybe you know how to put dummy args in and make it an actual function call instead of taking the func's address? That's probably be a pain, but maybe it would get around the bug.
Aug 12 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:j246df$2ael$1 digitalmars.com...
 "Adam D. Ruppe" <destructionator gmail.com> wrote in message 
 news:j242up$24so$1 digitalmars.com...
 There's no way I've found, aside from direct access (so not via
 getMembers) and seeing it it fails to compile.
I just gave it a try. I think I may be hitting against a bug in __traits(compiles) WRT private. This is the best I could get (Using DMD 2.054, Win): Note that "auto y = &(foo.d);" fails to compile as expected, but __traits(compiles) claims that should compile. It works for the non-function members though. I did the "auto x = &(...);" trick so I wouldn't have to deal with the function's params. Maybe you know how to put dummy args in and make it an actual function call instead of taking the func's address? That's probably be a pain, but maybe it would get around the bug.
Oops, I misread the line number. The line "auto y = &(foo.d);" DOES compile. So it's not a bug in __traits(compiles). But it may simply be a bug in private. In other words: Taking the address of a private member function (from some other module) is currently allowed (but seems wrong to me). If that's fixed, then my code *should* work. But private has practically never worked anyway :(
Aug 12 2011
parent "Nick Sabalausky" <a a.a> writes:
Ok, this seems to work for member functions (it returns false for 
non-functions, but I think that's fixable by just detecting "function vs not 
function" and then using the appropriate __traits(compiles)).

enum check = __traits(compiles, {
    alias ParameterTypeTuple!(__traits(getMember, Foo, name)) T;
    T t;
    __traits(getMember, foo, name)( t );
 });

I have not tested it on fancy arguments like ref/in/out/lazy/etc., or on 
functions with a return value. But it seems to work on void(void) and 
void(int).

Here's the full relevent code:

template check(string name)
{
    enum check = __traits(compiles, {
        alias ParameterTypeTuple!(__traits(getMember, Foo, name)) T;
        T t;
        __traits(getMember, foo, name)( t );
    });
}

// Any way to do this with foreach? Didn't work when I tried.
template checkMembers(members...)
{
    static if(members.length > 0)
    {
        // Check the first
        pragma(msg,
            members[0] ~ ": " ~
            (check!(members[0]) ? "true" : "false")
        );

        // Check the rest
        static if(members.length > 1)
            alias checkMembers!(members[1..$]) dummy;
    }
}

alias checkMembers!(__traits(allMembers, Foo)) dummy;
Aug 12 2011