How to get a single file syntax tree?

I’ve tried using libclang parse with CXTranslationUnit_SingleFileParse option, but it drop all nodes due to use of undeclared identifier. It works if remove the single file parse option, but it’s too slow as it parses all the headers it includes (which I don’t need).

I checked the api references, seems no way to keep the ast node that missing declared.

My goal is fetching syntax tree for specific file, without any included symbols.
Please point me out what’s the correct way to use with clang library (or libTooling or other internal api)

You could have a look here:
https://clang.llvm.org/docs/RAVFrontendAction.html

1 Like

It seems that not works as expected.

For example, the following source code, it just print foo.cpp:1:10: fatal error: 'foo.h' file not found and then exit.

#include "foo.h"
Foo::Foo() {
}

void Foo::test() {
	std::cout << "test" << n << std::endl;
}

void Foo::hello(int i, const char* msg) {
}

I copied some code from Tooling.cpp, and set to single file parse mode,

std::shared_ptr<PCHContainerOperations> PCHContainerOps = std::make_shared<PCHContainerOperations>();
CompilerInstance Compiler(std::move(PCHContainerOps));
Compiler.setInvocation(std::move(Invocation));
Compiler.setFileManager(Files.get());
Compiler.createDiagnostics(nullptr, false);
Compiler.getPreprocessorOpts().SingleFileParseMode = true;
Compiler.getDiagnosticOpts().IgnoreWarnings = true;

Using the RecursiveASTVisitor:

class DumpASTVisitor : public RecursiveASTVisitor<DumpASTVisitor>
{
public:
	explicit DumpASTVisitor(ASTContext* Context) : Context(Context) {}

	bool VisitDecl(Decl* D)
	{
		return true;
	}

private:
	ASTContext* Context;
};


DumpASTAction Action;
Compiler.ExecuteAction(Action);

The VisitDecl only got a TranslationUnitDecl, no other decls.

I want to get what is the Foo::Foo, Foo::test etc, no need to known if Foo it’s a class or namespace or somethine else. But it should have a token type.

In the example is a VisitCXXRecordDecl. There should be more Visit* methods.

No, I already used the based one VisitDecl(Decl* D), even add other Visit* helps nothing.
If I don’t use the single parse mode (allow parse the header), if works. But I want to ignore the header to speedup performance.

I’ll dig into the source code later, to see what happened with SingleFileParseMode .

From the page:

class FindNamedClassVisitor
  : public RecursiveASTVisitor<FindNamedClassVisitor> {
public:
  bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
    // For debugging, dumping the AST nodes will show which nodes are already
    // being visited.
    Declaration->dump();

    // The return value indicates whether we want the visitation to proceed.
    // Return false to stop the traversal of the AST.
    return true;
  }
};

I think you don’t get my point, I’m using SingleFileParseMode, it work if it set to false.
While debugging the sema parser code, I found that while parsing Foo::Foo() without the required header, it will just report as err_undeclared_var_use from SemaCXXScopeSpec.cpp BuildCXXNestedNameSpecifier.

And finally in Parser.cpp ParseExternalDeclaration returns nullptr means parsing with error.

So the problem should be that clang doesn’t support parsing “incomplete” code (such as without header)