Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Language IDEs » C / C++ IDE (CDT) » Retrieve ASTNode function body from referenced file via function name(CDT Plugin - Retrieval of function body referenced in a different file)
Retrieve ASTNode function body from referenced file via function name [message #1795019] Wed, 12 September 2018 19:48 Go to next message
Jan Cegin is currently offline Jan CeginFriend
Messages: 1
Registered: September 2018
Junior Member
Hello everyone!

I am new here, so if I posted this in a wrong section, please excuse me and let me know to move this to the PDE.
I am developing a plugin for the Eclipse CDT which collects Function bodies as CASTCompoundStatement which are later used in unit test generation.
This works fine using the ASTVisitor implementation, expect for one specific case -> when I am calling a function from a different file.

Example:
main.c
#include <stdlib.h>
#include <stdio.h>
#include "functions.h"

int main(void) {
  func1();
  func2();
  return 0;
}


functions.h
void func1(void);
void func2(void);


functions.c
#include "functions.h"

void func1(void) {
  printf("Function 1!\n");
}

void func2(void) {
  printf("Function 2!\n");
}


Now, knowing that I am calling functions func1 and func2 from the main.c, both of which are not defined in main.c, I would like to somehow access their CASTFunctionDeclarator nodes.
Thus I could get the function bodies and other things which are important for other parts of the plugin.

Is there a way how to retrieve the function bodies with me knowing their names/having their CASTFunctionCallExpression nodes?
Any kind of ideas are welcome, as I have been checking this for quite some time and couldn't find an answer.

Thank you.
Re: Retrieve ASTNode function body from referenced file via function name [message #1795126 is a reply to message #1795019] Sun, 16 September 2018 04:06 Go to previous message
Marc-André Laperle is currently offline Marc-André LaperleFriend
Messages: 233
Registered: July 2009
Senior Member
Hi Jan! I haven't used this API in a while but I can try to give you a general idea of what is needed. Since main.c and functions.c are two different source files (translation units), CDT (and compilers) would generate ASTs independently when you open the files. So there is no direct way to go from CASTFunctionCallExpression (main.c) to the CASTFunctionDeclarator as seen in functions.c but there is definitely a way to do what you want. In order to provide this kind of cross-translation-unit functionality, CDT as an index that takes care (among a lot of things) of associating a given symbol name to its definition. So, you would have to get the name of your CASTFunctionCallExpression, ask the index the location of the definition, get the AST of the file that contains that location, get the AST node at the location. For this to work, you need to make sure to have the code indexed. I don't know how you integrate your algorithm with the rest of CDT so I don't know if you do have an index computed. By default, if you have a C project within Eclipse, it will should be indexed.

Here are the steps I would try:
1. From the CASTFunctionCallExpression get a IBinding of the function name
2. Use IIndex.findNames(binding, FIND_DEFINITIONS) to get all the index names of the definitions (there could be multiple definitions in a project with multiple binaries, etc)
3. From the index name, use the location to get a translation unit (functions.c !) using CoreModelUtil.findTranslationUnitForLocation(indexLocation, cProject)
4. Get an AST for that translation unit, ITranslationUnit.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS). This can be slow, you might want to cache this if you need the AST for the same translation unit multiple times, but make sure the ASTs don't outlive the release of the index (see releaseReadLock in sample code)
5. Get a the node selector from the AST, ast.getNodeSelector(null), then find the node with selector.findEnclosingNode(indexName.getOffset(),indexName.getLength())
6. Poke around the node (getParent+instanceof) to find the IASTFunctionDeclarator

There might be some helpers to do this more simply, I don't know all of them.

Here's some sample code that I came up with (it's inside an ASTVisitor). Hopefully, this give you a feel of the API.
@Override
public int visit(IASTExpression expression) {
	if (expression instanceof IASTFunctionCallExpression) {
		IASTExpression functionNameExpression = ((IASTFunctionCallExpression) expression).getFunctionNameExpression();
		if (functionNameExpression instanceof IASTIdExpression) {
			IASTIdExpression idExpression = (IASTIdExpression) functionNameExpression;
			IBinding binding = idExpression.getName().resolveBinding();
			ICProject cProject = ast.getTranslationUnit().getOriginatingTranslationUnit().getCProject();
			IIndex index;
			try {
				index = CCorePlugin.getIndexManager().getIndex(cProject);
				index.acquireReadLock();
			} catch (CoreException e) {
				// log exception??
				return PROCESS_ABORT;
			} catch (InterruptedException e) {
				return PROCESS_ABORT;
			}
			try {
				IIndexName[] names = index.findNames(binding, IIndex.FIND_DEFINITIONS);
				if (names.length > 0) {
					IIndexName definitionIndexName = names[0];
					IIndexFileLocation indexFileLocation = definitionIndexName.getFile().getLocation();
					//CCorePlugin.getDefault().getCoreModel().getCModel();
					ITranslationUnit translationUnit = CoreModelUtil.findTranslationUnitForLocation(indexFileLocation, cProject);
					IASTTranslationUnit astOtherFile = translationUnit.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
					IASTNodeSelector selector = astOtherFile.getNodeSelector(null);
					IASTNode node = selector.findEnclosingNode(definitionIndexName.getNodeOffset(), definitionIndexName.getNodeLength());
					// This is probably going to always be a IASTName but maybe there are some other weird cases
					if (node instanceof IASTName) {
						ASTNodeProperty propertyInParent = node.getPropertyInParent();
						// Maybe this is being too careful and the "instanceof IASTFunctionDeclarator" is enough?
						if (propertyInParent == IASTDeclarator.DECLARATOR_NAME) {
							IASTNode parent = node.getParent();
							if (parent instanceof IASTFunctionDeclarator) {
								IASTFunctionDeclarator functionDeclarator = (IASTFunctionDeclarator) parent;
								System.out.println("success!");
							}	
						}
					}
				}	
			} catch (CoreException e) {
				// log exception??
				return PROCESS_ABORT;
			} finally {
				index.releaseReadLock();
			}

			
		}
	}
	return PROCESS_CONTINUE;
}


A good place to learn this kind of code is in org.eclipse.cdt.codan.checkers plugin and org.eclipse.cdt.ui/org.eclipse.cdt.internal.refactoring.
Previous Topic:Extend the Doxygen tag list
Next Topic:Enhancing the Doxygen Plug-in or new 'perspective'
Goto Forum:
  


Current Time: Wed Sep 26 12:16:28 GMT 2018

Powered by FUDForum. Page generated in 0.02115 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top