Best way to get SourceLocation of a Declarator?

Hi,

what's the best way to get a SourceLocation of a Declarator? I want to skip all Declarators from system headers, so my ActOnDeclarator looks like this:

   Action::DeclTy *
   ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
     SourceLocation loc = // loc of D
     SourceManager& sm = pp.getSourceManager();
     if (!sm.isInSystemHeader(loc)) {
       // do stuff
     }
     return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
   }

However, what's the best way to get a SourceLocation of a Declarator? I can use D.getIdentifierLoc(), but not all Declarators have an identifier (e.g. `struct s{};`). Likewise, I could use one of the TypeSpecLocs of the DeclSpec, but each of the typespecs is optional, too (e.g. `int a;` only has a TypeSpecType, `long a;` does not have a TypeSpecType location).

So, is there a general way to get the SourceLocation of a Declarator?

Thanks,
Nico

Hi,

what’s the best way to get a SourceLocation of a Declarator? I want to
skip all Declarators from system headers, so my ActOnDeclarator looks
like this:

Action::DeclTy *
ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
SourceLocation loc = // loc of D
SourceManager& sm = pp.getSourceManager();
if (!sm.isInSystemHeader(loc)) {
// do stuff
}
return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
}

However, what’s the best way to get a SourceLocation of a Declarator?
I can use D.getIdentifierLoc(), but not all Declarators have an
identifier (e.g. struct s{};). Likewise, I could use one of the
TypeSpecLocs of the DeclSpec, but each of the typespecs is optional,
too (e.g. int a; only has a TypeSpecType, long a; does not have a
TypeSpecType location).

I don’t believe this is true. Just to confirm, I added the following line to MinimalAction::ActOnDeclarator():

if (D.getDeclSpec().getTypeSpecTypeLoc().isValid())
printf(“we have a valid source location\n”);

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% cat xx.c
int a;
long b;

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% …/…/Debug/bin/clang -parse-noop xx.c
we have a valid source location
we have a valid source location

So, is there a general way to get the SourceLocation of a Declarator?

There isn’t. As you note above, many structure definitions don’t even have a top-level declarator.

In the past (in another compiler), I solved this problem by creating a node that represents the entire declaration. The declaration AST node could record the start/end (which would be uniform with how we implement ranges for statements). When I was working on the ObjC rewriter, I wished clang modeled it this way. Instead, I developed hacks to work around it.

If we are moving forward with Ted’s DeclGroup proposal, it might make sense to consider a Declaration AST node as well? It would certainly simplify source analysis tools in particular…

Thoughts?

snaroff

Hi,

identifier (e.g. `struct s{};`). Likewise, I could use one of the
TypeSpecLocs of the DeclSpec, but each of the typespecs is optional,
too (e.g. `int a;` only has a TypeSpecType, `long a;` does not have a
TypeSpecType location).

I don't believe this is true. Just to confirm, I added the following line to MinimalAction::ActOnDeclarator():

  if (D.getDeclSpec().getTypeSpecTypeLoc().isValid())
    printf("we have a valid source location\n");

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% cat xx.c
int a;
long b;

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% ../../Debug/bin/clang -parse-noop xx.c
we have a valid source location

$ touch empty.c
$ clang empty.c
we have a valid source location

I believe that's the `typedef char* __builtin_va_list` that's inserted by Preprocessor. So, there's no output for `long b;`.

So, is there a general way to get the SourceLocation of a Declarator?

There isn't. As you note above, many structure definitions don't even have a top-level declarator.

Ok, thanks.

In the past (in another compiler), I solved this problem by creating a node that represents the entire declaration. The declaration AST node could record the start/end (which would be uniform with how we implement ranges for statements).

While that's certainly useful in general, it doesn't help here, because there are no AST nodes when ActOnDeclarator() is called (it's part of the parser interface). But it's not a big deal for me, I was just wondering.

Nico

Hi,

identifier (e.g. `struct s{};`). Likewise, I could use one of the
TypeSpecLocs of the DeclSpec, but each of the typespecs is optional,
too (e.g. `int a;` only has a TypeSpecType, `long a;` does not have a
TypeSpecType location).

I don't believe this is true. Just to confirm, I added the following
line to MinimalAction::ActOnDeclarator():

if (D.getDeclSpec().getTypeSpecTypeLoc().isValid())
   printf("we have a valid source location\n");

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% cat xx.c
int a;
long b;

[steve-naroffs-imac-2:llvm/tools/clang] snaroff% ../../Debug/bin/
clang -parse-noop xx.c
we have a valid source location

$ touch empty.c
$ clang empty.c
we have a valid source location

I believe that's the `typedef char* __builtin_va_list` that's inserted
by Preprocessor. So, there's no output for `long b;`.

So, is there a general way to get the SourceLocation of a Declarator?

There isn't. As you note above, many structure definitions don't
even have a top-level declarator.

Ok, thanks.

In the past (in another compiler), I solved this problem by creating
a node that represents the entire declaration. The declaration AST
node could record the start/end (which would be uniform with how we
implement ranges for statements).

While that's certainly useful in general, it doesn't help here,
because there are no AST nodes when ActOnDeclarator() is called (it's
part of the parser interface). But it's not a big deal for me, I was
just wondering.

Sure. I thought you were fiddling with ActOnDeclarator() because the AST nodes didn't provide the info you needed.

Is this not the case?

Curious,

snaroff

While that's certainly useful in general, it doesn't help here,
because there are no AST nodes when ActOnDeclarator() is called (it's
part of the parser interface). But it's not a big deal for me, I was
just wondering.

Sure. I thought you were fiddling with ActOnDeclarator() because the AST nodes didn't provide the info you needed.

Is this not the case?

No, I'm fiddling with ActOnDeclarator just for the heck of it, to understand how clang's parts interact ( clang tutorial :stuck_out_tongue: -- obviously far from done).

Nico

Nico Weber wrote:

Hi,

what's the best way to get a SourceLocation of a Declarator? I want to skip all Declarators from system headers, so my ActOnDeclarator looks like this:

   Action::DeclTy *
   ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
     SourceLocation loc = // loc of D
     SourceManager& sm = pp.getSourceManager();
     if (!sm.isInSystemHeader(loc)) {
       // do stuff
     }
     return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
   }

However, what's the best way to get a SourceLocation of a Declarator? I can use D.getIdentifierLoc(), but not all Declarators have an identifier (e.g. `struct s{};`). Likewise, I could use one of the TypeSpecLocs of the DeclSpec, but each of the typespecs is optional, too (e.g. `int a;` only has a TypeSpecType, `long a;` does not have a TypeSpecType location).

So, is there a general way to get the SourceLocation of a Declarator?
  
Hi Nico,

ActOnDeclarator will be called when there is an identifier for the declaration, (if there isn't, it's erroneous declaration), so you can use D.getIdentifierLoc() for that.
If it's a only-declspec declaration (like in "struct s{};"), ParsedFreeStandingDeclSpec will be called, and you can use DS.getSourceRange() then (DS is the DeclSpec passed to ParsedFreeStandingDeclSpec).

-Argiris

Nico Weber wrote:

No, I'm fiddling with ActOnDeclarator just for the heck of it, to understand how clang's parts interact ( clang tutorial :stuck_out_tongue: -- obviously far from done).
  
Your tutorials are very informative, good job! Maybe they can be linked by the clang page when they are done.

-Argiris

Nico, this looks really nice! When it gets closer to being done, are you interested in hosting it on clang.llvm.org? I think it could be useful to a whole lot of people,

-Chris

No, I'm fiddling with ActOnDeclarator just for the heck of it, to
understand how clang's parts interact ( clang tutorial
:stuck_out_tongue: -- obviously far from done).

Nico, this looks really nice! When it gets closer to being done, are you interested in hosting it on clang.llvm.org? I think it could be useful to a whole lot of people,

Sure, that'd be great. However, it might take a few more days (weeks?) until it's done.

Nico

No hurry! That would be great,

-Chris

No, I'm fiddling with ActOnDeclarator just for the heck of it, to
understand how clang's parts interact ( clang tutorial
:stuck_out_tongue: -- obviously far from done).

Nico, this looks really nice! When it gets closer to being done,
are you interested in hosting it on clang.llvm.org? I think it
could be useful to a whole lot of people,

Sure, that'd be great. However, it might take a few more days (weeks?)
until it's done.

I read some of it, and it appears very good indeed. I noticed a few things, and I figure I might as well provide a bit of feedback :slight_smile:

(for example, variables that have the old name but are in a different namespace, and so on)

Wouldn't it be better to refer to scope rather than namespaces? Unlike namespaces, they aren't specific to C++, and neither are handled terribly gracefully by grep/sed/whatever anyway…

(After trying Eclipse with its integrated Java compiler, I can't wait for the day where editors do the same with clang!)

For performance reasons, clang does not have a separate preprocessor program, but does preprocessing while lexing.

It's my impression from the documentation[1] that this is much more than an optimisation. It seems to be what allows clang to track everything back to the original source rather than the pre-processed intermediate. “Great feature” comes to mind :wink:

[1] <http://clang.llvm.org/comparison.html&gt;