All Downloads are FREE. Search and download functionalities are using the official Maven repository.

refdiff.parsers.c.CCstVisitor Maven / Gradle / Ivy

package refdiff.parsers.c;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTASMDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTArrayDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTArrayDesignator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTArrayModifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTArrayRangeDesignator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTArraySubscriptExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTBinaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTBreakStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCaseStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCastExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCompositeTypeSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCompoundStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCompoundStatementExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTConditionalExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTContinueStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDeclarationStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDefaultStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDesignatedInitializer;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDoStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTElaboratedTypeSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTEnumerationSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTEqualsInitializer;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTExpressionList;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTExpressionStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTFieldDesignator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTFieldReference;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTForStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTFunctionCallExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTFunctionDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTFunctionDefinition;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTGotoStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTIfStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTInitializerList;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTLabelStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTNullStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTParameterDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTPointer;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTProblem;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTProblemDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTProblemExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTProblemStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTReturnStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSwitchStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTypeId;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTypeIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTypeIdInitializerExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTypedefNameSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTUnaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTWhileStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.GNUCASTGotoStatement;

import refdiff.core.cst.HasChildrenNodes;
import refdiff.core.cst.Location;
import refdiff.core.cst.Parameter;
import refdiff.core.cst.CstNode;
import refdiff.core.cst.CstNodeRelationship;
import refdiff.core.cst.CstNodeRelationshipType;
import refdiff.core.cst.CstRoot;

public class CCstVisitor extends ASTGenericVisitor {

	private static final char FOLDER_SEPARATOR = '/';
	private AtomicInteger id;
	private CstNode currentNode;
	private CstNode currentRelationshipN1;
	private Map nodesHash = new HashMap();
	private CstRoot cstRoot;
	private CstNode programNode;
	private String waitingName;
	private String waitingBodyLocation = "";
	private String waitingType;
	private String maybeWaitingArray;
	private String fileName;
	private CharSequence fileContent;
	private String maybePointer = "";

	public CCstVisitor(CstRoot cstRoot, String fileName, CharSequence fileContent, AtomicInteger id) {
		super(true);
		this.cstRoot = cstRoot;
		this.fileName = fileName;
		this.fileContent = fileContent;
		this.id = id;
	}
	
	@Override
	protected int genericVisit(IASTNode iastNode) {
		if (!this.shouldSkip(iastNode)) {
			if (this.maybeWaitingArray != null && !(iastNode instanceof CASTArrayModifier)) {
				this.maybeWaitingArray = null;
			}
			
			if (this.maybePointer != null && !(iastNode instanceof IASTName)) {
				this.maybePointer = "";
			}
			
			if (iastNode instanceof CASTFunctionCallExpression) {
				this.currentRelationshipN1 = (CstNode) this.getRASTParent(iastNode);
				this.waitingName = "Relationship";
			}
			else if (iastNode instanceof CASTParameterDeclaration) {
				this.waitingName = "Parameter";
				this.waitingType = "Parameter";
			}
			else if (iastNode instanceof CASTCompoundStatement) {
				if (this.waitingBodyLocation.equals("FunctionDeclaration")) {
					int offset = ((CASTCompoundStatement) iastNode).getFileLocation().getNodeOffset();
					int length = ((CASTCompoundStatement) iastNode).getRawSignature().length();
					
					Location location = this.currentNode.getLocation();
					
					// Ignore opening e closing brackets
					location.setBodyBegin(offset + 1);
					location.setBodyEnd(offset + length - 1);
					
					this.waitingBodyLocation = "";
				}
			}
			else if (iastNode instanceof CASTSimpleDeclSpecifier) {
				if (this.waitingType != null && this.waitingType.equals("Parameter")) {
					this.appendParameterType(this.getType((CASTSimpleDeclSpecifier) iastNode));
				}
			}
			else if (iastNode instanceof CASTArrayModifier) {
				if (this.maybeWaitingArray != null && this.maybeWaitingArray.equals("Parameter")) {
					CstNode parentNode = (CstNode) this.getRASTParent(iastNode);
					
					List parameters = parentNode.getParameters();
					Parameter lastParameter = parameters.get(parameters.size() - 1);
					
					lastParameter.setName(lastParameter.getName() + "[]");
				}
				
				this.maybeWaitingArray = null;
			}
			else if (iastNode instanceof CASTPointer) {
				this.maybePointer = "*";
			}
			else if (iastNode instanceof IASTName) {
				if (((iastNode.getParent() instanceof CASTTypedefNameSpecifier) || (iastNode.getParent() instanceof CASTElaboratedTypeSpecifier)) 
						&& this.waitingType != null && this.waitingType.equals("Parameter")) {
					this.appendParameterType(((IASTName) iastNode).toString());
				}
				else if (this.waitingName != null) {
					String name = ((IASTName) iastNode).toString();
					
					boolean shouldClear = true;

					if (this.waitingName.equals("FunctionDeclaration")) {
						if (iastNode.getParent() instanceof CASTTypedefNameSpecifier 
								|| iastNode.getParent() instanceof CASTElaboratedTypeSpecifier) {
							shouldClear = false;
						}
						else {
							this.currentNode.setSimpleName(name);
							this.currentNode.setLocalName(name + "()");							
						}
					}
					else if (this.waitingName.equals("Parameter")) {
						Parameter parameter = new Parameter();
						parameter.setName(this.maybePointer + name);
						
						CstNode parentNode = (CstNode) this.getRASTParent(iastNode);
						parentNode.getParameters().add(parameter);
												
						this.maybeWaitingArray = "Parameter";
					}
					else if (this.waitingName.equals("Relationship")) {
						CstNode n2 = this.getBySimpleName(this.maybePointer + name);
						if (n2 != null) {
							if (!this.hasRelationship(
									this.cstRoot, this.currentRelationshipN1, n2, CstNodeRelationshipType.USE)) {
								CstNodeRelationship relationship = new CstNodeRelationship(
										CstNodeRelationshipType.USE, 
										this.currentRelationshipN1.getId(), 
										n2.getId());
								this.cstRoot.getRelationships().add(relationship);								
							}
						}
						
						this.currentRelationshipN1 = null;
					}
					
					if (shouldClear) {
						this.waitingName = null;
						this.maybePointer = "";						
					}
				}
			}
			else {
				boolean createNode = true;
				
				if (iastNode instanceof CASTFunctionDefinition) {
					this.waitingName = "FunctionDeclaration";
					this.waitingBodyLocation = "FunctionDeclaration";
				}
				else if (iastNode instanceof CASTFunctionDeclarator) {
					if (iastNode.getParent() instanceof CASTFunctionDefinition) {
						createNode = false;
					}
					else {
						this.waitingName = "FunctionDeclaration";
						this.waitingBodyLocation = "";
					}
				}
				
				if (createNode) {
					CstNode node = this.createNode((ASTNode) iastNode);
					this.currentNode = node;
					if (iastNode instanceof CASTTranslationUnit) {
						this.programNode = node;
					}
				}
			}				
		}

		return PROCESS_CONTINUE;
	}
	
	private void appendParameterType(String type) {
		String localName = this.currentNode.getLocalName();
		
		if (localName != null) {
			int closingParenthesisIndex = localName.indexOf(")");
			
			if (localName.charAt(closingParenthesisIndex - 1) != '(') {
				type = ", " + type;
			}
			
			StringBuilder newLocalNameBuilder = new StringBuilder();
			newLocalNameBuilder.append(localName.substring(0, closingParenthesisIndex));
			newLocalNameBuilder.append(type);
			newLocalNameBuilder.append(")");
			
			this.currentNode.setLocalName(newLocalNameBuilder.toString());			
		}
		
		this.waitingType = null;
		this.maybeWaitingArray = null;
	}
	
	private CstNode createNode(ASTNode astNode) {
		CstNode cstNode = new CstNode(this.id.get());
		
		int offset = astNode.getFileLocation().getNodeOffset();
		int length = astNode.getRawSignature().length();
		
		if (astNode instanceof CASTTranslationUnit) {
			int lastSeparatorIndex = this.fileName.lastIndexOf(FOLDER_SEPARATOR);
			
			String path = "";
			if (lastSeparatorIndex != -1) {
				path = this.fileName.substring(0, lastSeparatorIndex + 1);	
			}
			
			String fileNameWithoutPath = this.fileName.substring(lastSeparatorIndex + 1);

			cstNode.setNamespace(path);
			cstNode.setSimpleName(fileNameWithoutPath);
			cstNode.setLocalName(fileNameWithoutPath);
		}
		
		cstNode.setType(this.getRASTType(astNode));
		
		Location location = new Location();
		location.setBegin(offset);
		location.setLine(Location.findLineNumber(offset, fileContent));
		location.setEnd(offset + length);
		location.setFile(this.fileName);
		
		if (astNode instanceof CASTTranslationUnit) {
			location.setBodyBegin(offset);
			location.setBodyEnd(offset + length);
		}
		else if (astNode instanceof CASTFunctionDeclarator) {
			location.setBodyBegin(offset + length);
			location.setBodyEnd(offset + length);
		}
		
		cstNode.setLocation(location);
		
		if (astNode instanceof CASTFunctionDefinition
				|| astNode instanceof CASTFunctionDeclarator) {
			cstNode.setSimpleName("");
			cstNode.setLocalName("()");			
		}
		
		this.id.incrementAndGet();
		
		HasChildrenNodes parentNode = this.getRASTParent(astNode);
		
		parentNode.addNode(cstNode);

		this.nodesHash.put(astNode.hashCode(), cstNode);
		
		return cstNode;
	}
	
	private String getRASTType(ASTNode astNode) {
		if (astNode instanceof CASTTranslationUnit) {
			return "Program";
		}
		else if (astNode instanceof CASTFunctionDefinition || astNode instanceof CASTFunctionDeclarator) {
			return "FunctionDeclaration";
		}
		else if (astNode instanceof CASTParameterDeclaration) {
			return "Parameter";
		}
		
		throw new RuntimeException("Not predicted type: " + astNode.getClass().getName());
	}
	
	private boolean shouldSkip(IASTNode iastNode) {
		return iastNode instanceof CASTExpressionStatement
				|| iastNode instanceof CASTIdExpression 
				|| iastNode instanceof CASTLiteralExpression
				|| iastNode instanceof CASTTypedefNameSpecifier
				|| (iastNode instanceof CASTDeclarator && 
						!iastNode.getClass().getSimpleName().equals("CASTFunctionDeclarator"))
				|| iastNode instanceof CASTReturnStatement
				|| iastNode instanceof CASTDeclarationStatement
				|| iastNode instanceof CASTSimpleDeclaration
				|| iastNode instanceof CASTUnaryExpression
				|| iastNode instanceof CASTBinaryExpression
				|| iastNode instanceof CASTArrayDeclarator 
				|| iastNode instanceof CASTArraySubscriptExpression
				|| iastNode instanceof CASTEqualsInitializer
				|| iastNode instanceof CASTIfStatement
				|| iastNode instanceof CASTTypeIdExpression
				|| iastNode instanceof CASTTypeId
				|| iastNode instanceof CASTFieldReference
				|| iastNode instanceof CASTElaboratedTypeSpecifier
				|| iastNode instanceof CASTCastExpression
				|| iastNode instanceof CASTCompositeTypeSpecifier
				|| iastNode instanceof CASTInitializerList
				|| iastNode instanceof CASTForStatement
				|| iastNode instanceof CASTWhileStatement
				|| iastNode instanceof CASTGotoStatement
				|| iastNode instanceof CASTConditionalExpression
				|| iastNode instanceof CASTContinueStatement
				|| iastNode instanceof CASTProblemStatement
				|| iastNode instanceof CASTProblem
				|| iastNode instanceof CASTBreakStatement
				|| iastNode instanceof CASTLabelStatement
				|| iastNode instanceof CASTExpressionList
				|| iastNode instanceof CASTNullStatement
				|| iastNode instanceof CASTDoStatement
				|| iastNode instanceof CASTEnumerationSpecifier
				|| iastNode instanceof CASTEnumerator
				|| iastNode instanceof CASTSwitchStatement
				|| iastNode instanceof CASTCaseStatement
				|| iastNode instanceof CASTDesignatedInitializer
				|| iastNode instanceof CASTFieldDesignator
				|| iastNode instanceof CASTDefaultStatement
				|| iastNode instanceof CASTProblemDeclaration
				|| iastNode instanceof CASTArrayDesignator
				|| iastNode instanceof CASTProblemExpression
				|| iastNode instanceof CASTTypeIdInitializerExpression
				|| iastNode instanceof GNUCASTGotoStatement
				|| iastNode instanceof CASTCompoundStatementExpression
				|| iastNode instanceof CASTASMDeclaration
				|| iastNode instanceof CASTArrayRangeDesignator;
	}
	
	private HasChildrenNodes getRASTParent(IASTNode iastNode) {
		if (iastNode instanceof CASTTranslationUnit) {
			return this.cstRoot;
		}
		
		CstNode cstParent = null;
		iastNode = iastNode.getParent();
		
		while (cstParent == null && iastNode != null) {
			cstParent = this.nodesHash.get(iastNode.hashCode());
			iastNode = iastNode.getParent();
		}
		
		if (cstParent == null) {
			cstParent = this.currentNode;
		}
		
		return cstParent;
	}
	
	private CstNode getBySimpleName(String simpleName) {
		return this.searchBySimpleName(this.programNode, simpleName);
	}
	
	private String getType(IASTSimpleDeclSpecifier node) {
		int type = node.getType();
		
		if (type == IASTSimpleDeclSpecifier.t_auto) { 
			return "auto";
		}
		else if (type == IASTSimpleDeclSpecifier.t_bool) {
			return "Bool";
		}
		else if (type == IASTSimpleDeclSpecifier.t_char) {
			return "char";
		}
		else if (type == IASTSimpleDeclSpecifier.t_char16_t) {
			return "char16_t";
		}
		else if (type == IASTSimpleDeclSpecifier.t_char32_t) {
			return "char32_t";
		}
		else if (type == IASTSimpleDeclSpecifier.t_decltype) {
			return "decltype";
		}
		else if (type == IASTSimpleDeclSpecifier.t_double) {
			return "double";
		}
		else if (type == IASTSimpleDeclSpecifier.t_float) {
			return "float";
		}
		else if (type == IASTSimpleDeclSpecifier.t_int) {
			return "int";
		}
		else if (type == IASTSimpleDeclSpecifier.t_typeof) {
			return "typeof";
		}
		else if (type == IASTSimpleDeclSpecifier.t_void) {
			return "void";
		}
		else if (type == IASTSimpleDeclSpecifier.t_wchar_t) {
			return "wchar_t";
		}
		
		return null;
	}
	
	private boolean hasRelationship(CstRoot root, CstNode n1, CstNode n2, CstNodeRelationshipType type) {
		for (CstNodeRelationship relationship : root.getRelationships()) {
			if (relationship.getType().equals(type)
					&& ((relationship.getN1() == n1.getId() && relationship.getN2() == n2.getId()) 
							|| (relationship.getN2() == n1.getId() && relationship.getN1() == n2.getId()))) {
				return true;
			}
		}
		
		return false;
	}
	
	private CstNode searchBySimpleName(CstNode node, String simpleName) {
		if (node.getSimpleName() != null && node.getSimpleName().equals(simpleName)) {
			return node;
		}

		for (CstNode child : node.getNodes()) {
			CstNode found = this.searchBySimpleName(child, simpleName);
			if (found != null) {
				return found;
			}
		}

		return null;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy