Now, what's the best method to find all global variable definitions?
(global functions are not interesting, and I don't want to find
globals form system headers).
Right now, I'm trying to overwrite ActOnDeclarator. In there, I only
look at variables with FileContext, and reject everything that is
`extern` (I only want the definitions of globals). Furthermore, I try
to skip functions by checking for PQ_FunctionSpecifier, but that does
not seem to skip all functions (for example, the `main` function of my
test input program).
Right... it would be easier to do this from an ASTConsumer, where you
would have access to types. Fundamentally, in C, it's impossible to
tell apart a global function declaration and a global variable
declaration without resolving typedefs and __typeof expressions.
Since that's beyond the scope of the parser, you'll either need to use
Sema, do these yourself, or be a bit conservative about printing out
things that aren't actually globals.
Examples of function declarations without an explicit type declarator:
typedef int x();
x z;
__typeof(z) r;
Also, with AST information, you can easily do other interesting
things, like printing the canonical type (the type stripped of
typedefs), or printing out all globals of a particular type, or
pretty-printing initializers, or more easily supporting C++
namespaces/classes using a visitor pattern.
If you're willing to be conservative with the cases of declaring a
function with __typeof or typedef, it isn't too hard. The check you
need is for whether the outermost type declarator is a function type
declarator (untested, but something like
"D.getTypeObject(D.getNumTypeObjects() - 1).Kind ==
DeclaratorChunk::Function").
PQ_FunctionSpecifier isn't even close to what you want; it essentially
tracks whether "inline" was specified on the declaration.
If you want to try and resolve typedefs, try looking at the
implementation of MinimalAction in clang/lib/Parser/MinimalAction.cpp.
Resolving __typeof would require implementing a large chunk of Sema,
so that's probably not something you want to mess with.
And it does not skip stuff that comes from angle-
bracket includes:
clang/lib/Sema/SemaDecl.cpp does this as follows:
SourceManager &SrcMgr = Context.getSourceManager();
HeaderSearch &HdrInfo = PP.getHeaderSearchInfo();
const FileEntry *OldDeclFile = SrcMgr.getFileEntryForLoc(Old->getLocation());
if (OldDeclFile) {
DirectoryLookup::DirType OldDirType = HdrInfo.getFileDirFlavor(OldDeclFile);
// Allow reclarations in both SystemHeaderDir and ExternCSystemHeaderDir.
if (OldDirType != DirectoryLookup::NormalHeaderDir)
return New;
}
That said, we should probably move this into some sort of helper
method on the Preprocessor class or something like that. Would
someone more familiar with the Preprocessor mind commenting?
Action::DeclTy *
ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
// Print names of global variables
if (D.getContext() == Declarator::FileContext) {
IdentifierInfo *II = D.getIdentifier();
const DeclSpec& DS = D.getDeclSpec();
if (DS.getStorageClassSpec() != DeclSpec::SCS_extern
&& (DS.getParsedSpecifiers() &
DeclSpec::PQ_FunctionSpecifier) == 0) {
cerr << "Found global declarator " << II->getName()
<< " " << D.getNumTypeObjects() << endl;
}
}
The last line of this method must be "return
MinimalAction::ActOnDeclarator(S, D, LastInGroup);"; otherwise, you'll
mess up the implementation of MinimalAction::isTypeName(), which in
turn will cause parse errors.
Can you give me a few hints where I should look to add that
functionality?
If you want to contribute it to clang? My first instinct is
clang/Driver/ASTConsumers.cpp, assuming you wrote an implementation as
an ASTConsumer. That said, I'm not sure how useful this would be; if
anyone else would find this useful, please comment.
-Eli