| /******************************************************************************* |
| * 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); |
| } |
| } |