blob: 212ae06c471bd3e4b7fec1fa6e4b96df3f938a7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2016 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ILabel;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
/**
* Base class for {@link CVisitor} and {@link CPPVisitor}
*/
public class ASTQueries {
private static class NameSearch extends ASTVisitor {
private boolean fFound;
NameSearch() {
super(false);
shouldVisitAmbiguousNodes= true;
shouldVisitNames= true;
}
public void reset() {
fFound= false;
}
public boolean foundName() {
return fFound;
}
@Override
public int visit(IASTName name) {
fFound= true;
return PROCESS_ABORT;
}
@Override
public int visit(ASTAmbiguousNode node) {
IASTNode[] alternatives= node.getNodes();
for (IASTNode alt : alternatives) {
if (!alt.accept(this))
return PROCESS_ABORT;
}
return PROCESS_CONTINUE;
}
}
private static NameSearch NAME_SEARCH= new NameSearch();
/**
* Tests whether the given node can contain ast-names, suitable to be used before ambiguity
* resolution.
*/
public static boolean canContainName(IASTNode node) {
if (node == null)
return false;
NAME_SEARCH.reset();
node.accept(NAME_SEARCH);
return NAME_SEARCH.foundName();
}
/**
* Returns the outermost declarator the given {@code declarator} nests within, or
* the given {@code declarator} itself.
*/
public static IASTDeclarator findOutermostDeclarator(IASTDeclarator declarator) {
IASTDeclarator outermost= null;
IASTNode candidate= declarator;
while (candidate instanceof IASTDeclarator) {
outermost= (IASTDeclarator) candidate;
candidate= outermost.getParent();
}
return outermost;
}
/**
* Returns the innermost declarator nested within the given {@code declarator}, or
* the given {@code declarator} itself.
*/
public static IASTDeclarator findInnermostDeclarator(IASTDeclarator declarator) {
IASTDeclarator innermost= null;
while (declarator != null) {
innermost= declarator;
declarator= declarator.getNestedDeclarator();
}
return innermost;
}
/**
* Searches for the innermost declarator that contributes the the type declared.
*/
public static IASTDeclarator findTypeRelevantDeclarator(IASTDeclarator declarator) {
if (declarator == null)
return null;
IASTDeclarator result= findInnermostDeclarator(declarator);
while (result.getPointerOperators().length == 0
&& !(result instanceof IASTFieldDeclarator)
&& !(result instanceof IASTFunctionDeclarator)
&& !(result instanceof IASTArrayDeclarator)) {
final IASTNode parent= result.getParent();
if (parent instanceof IASTDeclarator) {
result= (IASTDeclarator) parent;
} else {
return result;
}
}
return result;
}
/**
* Traverses parent chain of the given node and returns the first node of the given type.
* @param node the start node
* @param type the type to look for
* @return the node itself or its closest ancestor that has the given type, or {@code null}
* if no such node is found.
*/
@SuppressWarnings("unchecked")
public static <T extends IASTNode> T findAncestorWithType(IASTNode node, Class<T> type) {
while (node != null && !type.isInstance(node)) {
node = node.getParent();
}
return (T) node;
}
/**
* Searches for the function enclosing the given node. May return {@code null}.
*/
public static IBinding findEnclosingFunction(IASTNode node) {
IASTFunctionDefinition functionDefinition = findAncestorWithType(node, IASTFunctionDefinition.class);
if (functionDefinition == null)
return null;
IASTDeclarator dtor= findInnermostDeclarator(functionDefinition.getDeclarator());
if (dtor != null) {
IASTName name= dtor.getName();
if (name != null) {
return name.resolveBinding();
}
}
return null;
}
/**
* Extracts the active declarations from an array of declarations.
*/
public static IASTDeclaration[] extractActiveDeclarations(IASTDeclaration[] allDeclarations, int size) {
IASTDeclaration[] active;
if (size == 0) {
active= IASTDeclaration.EMPTY_DECLARATION_ARRAY;
} else {
active= new IASTDeclaration[size];
int j= 0;
for (int i = 0; i < size; i++) {
IASTDeclaration d= allDeclarations[i];
if (d.isActive()) {
active[j++]= d;
}
}
active= ArrayUtil.trim(active, j);
}
return active;
}
public static boolean isSameType(IType type1, IType type2) {
if (type1 == type2)
return true;
if (type1 == null || type2 == null)
return false;
return type1.isSameType(type2);
}
protected static boolean areArraysOfTheSameElementType(IType t1, IType t2) {
if (t1 instanceof IArrayType && t2 instanceof IArrayType) {
IArrayType a1 = (IArrayType) t1;
IArrayType a2 = (IArrayType) t2;
return isSameType(a1.getType(), a2.getType());
}
return false;
}
/**
* Check whether 'ancestor' is an ancestor of 'descendant' in the AST.
*/
public static boolean isAncestorOf(IASTNode ancestor, IASTNode descendant) {
do {
if (descendant == ancestor)
return true;
descendant = descendant.getParent();
} while (descendant != null);
return false;
}
protected static boolean isLabelReference(IASTNode node) {
boolean labelReference = false;
IASTNode parent = node.getParent();
if (parent instanceof IASTUnaryExpression) {
int operator = ((IASTUnaryExpression) parent).getOperator();
labelReference = operator == IASTUnaryExpression.op_labelReference;
}
return labelReference;
}
private static class FindLabelsAction extends ASTVisitor {
public IASTLabelStatement[] labels = IASTLabelStatement.EMPTY_ARRAY;
public FindLabelsAction() {
shouldVisitStatements = true;
}
@Override
public int visit(IASTStatement statement) {
if (statement instanceof IASTLabelStatement) {
labels = ArrayUtil.append(labels, (IASTLabelStatement) statement);
}
return PROCESS_CONTINUE;
}
}
protected static ILabel[] getLabels(IASTFunctionDefinition functionDefinition) {
FindLabelsAction action = new FindLabelsAction();
functionDefinition.accept(action);
ILabel[] result = ILabel.EMPTY_ARRAY;
if (action.labels != null) {
for (int i = 0; i < action.labels.length && action.labels[i] != null; i++) {
IASTLabelStatement labelStatement = action.labels[i];
IBinding binding = labelStatement.getName().resolveBinding();
if (binding != null)
result = ArrayUtil.append(result, (ILabel) binding);
}
}
return ArrayUtil.trim(result);
}
protected static IBinding resolveLabel(IASTName labelReference) {
char[] labelName = labelReference.toCharArray();
IASTFunctionDefinition functionDefinition =
findAncestorWithType(labelReference, IASTFunctionDefinition.class);
if (functionDefinition != null) {
for (ILabel label : getLabels(functionDefinition)) {
if (CharArrayUtils.equals(label.getNameCharArray(), labelName)) {
return label;
}
}
}
// Label not found.
return new ProblemBinding(labelReference, IProblemBinding.SEMANTIC_LABEL_STATEMENT_NOT_FOUND,
labelName);
}
}