Declaration name qualifiers.

Hello.

In the C++ AST, name qualifications are stored using NestedNameSpecifier objects. These are currently used in some expression nodes (e.g., DeclRefExpr and MemberExpr), some declaration nodes (e.g., UsingDirectiveDecl and NamespaceAliasDecl) and some type nodes (e.g., QualifiedNameType and TypenameType).

However, there are other AST nodes that can be qualified in the program sources but are not currently provided by a NestedNameSpecifier.
We would like to modify these AST nodes so that they can provide the required info to applications working at the program source level. Namely, we would like to make sure that, whenever a name qualification can appear in the source code, then it is possible to obtain from the corresponding AST node a NestedNameSpecifier* (for the qualifier) and a SourceRange (for the start/end locations of the qualifier in the sources).

Would this be reasonable from the point of view of clang's designers?

If so, the next step is to identify all AST nodes that need such an addition. In our opinion this is needed at least for
   - VarDecl
   - FunctionDecl (and its derived classes)
   - CXXRecordDecl
   - EnumDecl

Is this list complete?
It seems that TemplateDecl and Friend(Template)Decl do not need to store such a qualifier, since it can be stored in the actual declaration they refer too (coorect?).
What about the ObjC nodes?

As soon as we have a complete list of nodes to be "upgraded", we should be able to identify a minimum set of nodes in the AST hierarchies where these two data (NNS and range) will be added.

For instance, one option would be to add these data to

   - DeclarationDecl (covering both VarDecl and FunctionDecl, but also FieldDecl, where such a name qualifier seems to be not really needed);

   - TagDecl (covering both EnumDecl and CXXRecordDecl, but again also RecordDecl where it is not needed).

Would that be OK?

Regards,
Enea Zaffanella.

Enea Zaffanella wrote:

Hello.

In the C++ AST, name qualifications are stored using NestedNameSpecifier objects. These are currently used in some expression nodes (e.g., DeclRefExpr and MemberExpr), some declaration nodes (e.g., UsingDirectiveDecl and NamespaceAliasDecl) and some type nodes (e.g., QualifiedNameType and TypenameType).

However, there are other AST nodes that can be qualified in the program sources but are not currently provided by a NestedNameSpecifier.
We would like to modify these AST nodes so that they can provide the required info to applications working at the program source level.

Please find attached a patch implementing the proposal above.
The patch is based on revision 98253 and passes all tests.

Cheers,
Enea Zaffanella.

Qualifier.patch (81.9 KB)

Enea Zaffanella wrote:

Enea Zaffanella wrote:

Hello.

In the C++ AST, name qualifications are stored using NestedNameSpecifier objects. These are currently used in some expression nodes (e.g., DeclRefExpr and MemberExpr), some declaration nodes (e.g., UsingDirectiveDecl and NamespaceAliasDecl) and some type nodes (e.g., QualifiedNameType and TypenameType).

However, there are other AST nodes that can be qualified in the program sources but are not currently provided by a NestedNameSpecifier.
We would like to modify these AST nodes so that they can provide the required info to applications working at the program source level.

Please find attached a patch implementing the proposal above.
The patch is based on revision 98253 and passes all tests.

Sorry, I just realized that I attached the wrong file.
Here is the correct one.

Enea.

Qualifier.patch (82.4 KB)

I'm not okay with adding 2-3 pointers to every DeclaratorDecl for what's an uncommon case(*) even in C++. Please use a QualType-like hack here; that is to say, please make the DeclInfo field a PointerUnion<TypeSourceInfo*,UncommonData*> where UncommonData is a private struct holding the qualifier information (and the TypeSourceInfo*, of course).

I'm pretty sure you don't need this in TagDecl; I don't think enums can be declared out-of-line, so it could be pushed down to CXXRecordDecl at least. It would be nice if there were a similar space-saving hack you could use there, but fast access to a class's DefinitionData is much more important than fast access to a declarator's TypeSourceInfo. Maybe a side-table in the ASTContext?

(*) By all measures. Every scoped declaration necessarily has at least one unscoped previous declaration, headers contain primarily unscoped declarations, and local declarations are never scoped.

John.

<Qualifier.patch>

I'm not okay with adding 2-3 pointers to every DeclaratorDecl for what's an uncommon case(*) even in C++. Please use a QualType-like hack here; that is to say, please make the DeclInfo field a PointerUnion<TypeSourceInfo*,UncommonData*> where UncommonData is a private struct holding the qualifier information (and the TypeSourceInfo*, of course).

I agree.

I'm pretty sure you don't need this in TagDecl; I don't think enums can be declared out-of-line, so it could be pushed down to CXXRecordDecl at least.

C++0x allows forward declarations (and, therefore, out-of-line definitions) of enums, and it's also a GNU extension. So we do need this in TagDecl.

  - Doug

Douglas Gregor wrote:

<Qualifier.patch>

I'm not okay with adding 2-3 pointers to every DeclaratorDecl for
what's an uncommon case(*) even in C++. Please use a QualType-like
hack here; that is to say, please make the DeclInfo field a
PointerUnion<TypeSourceInfo*,UncommonData*> where UncommonData is a
private struct holding the qualifier information (and the
TypeSourceInfo*, of course).

I agree.

>

I'm pretty sure you don't need this in TagDecl; I don't think
enums can be declared out-of-line, so it could be pushed down to
CXXRecordDecl at least.

C++0x allows forward declarations (and, therefore, out-of-line
definitions) of enums, and it's also a GNU extension. So we do need
this in TagDecl.

- Doug

Please find attached the patch revised as suggested.

We now use internal ExtInfo structures in both DeclaratorDecl and in TagDecl nodes. In the latter, the ExtInfo structure only contains info about the name qualifier; it is stored in a PointerUnion with the old TypedefForAnonDecl* field, since they could not occur together.

Cheers,
Enea Zaffanella.

Qualifier-2.patch (21.5 KB)

Douglas Gregor wrote:

<Qualifier.patch>

I'm not okay with adding 2-3 pointers to every DeclaratorDecl for
what's an uncommon case(*) even in C++. Please use a QualType-like
hack here; that is to say, please make the DeclInfo field a
PointerUnion<TypeSourceInfo*,UncommonData*> where UncommonData is a
private struct holding the qualifier information (and the
TypeSourceInfo*, of course).

I agree.

>

I'm pretty sure you don't need this in TagDecl; I don't think
enums can be declared out-of-line, so it could be pushed down to
CXXRecordDecl at least.

C++0x allows forward declarations (and, therefore, out-of-line
definitions) of enums, and it's also a GNU extension. So we do need
this in TagDecl.
- Doug

Please find attached the patch revised as suggested.

Thanks! This looks very nice; committed as r98540 with a few tweaks.

We now use internal ExtInfo structures in both DeclaratorDecl and in TagDecl nodes. In the latter, the ExtInfo structure only contains info about the name qualifier; it is stored in a PointerUnion with the old TypedefForAnonDecl* field, since they could not occur together.

Very nice; I'd forgotten about that field on TagDecl.

John.