blob: d1f5cf77ea82e6ec5a6637c11e23bb309903f168 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2012 IBM Corporation 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:
* Andrew Niefer (IBM Rational Software) - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemHolder;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.ILabel;
import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.c.ICASTPointer;
import org.eclipse.cdt.core.dom.ast.c.ICASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTTypedefNameSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICArrayType;
import org.eclipse.cdt.core.dom.ast.c.ICCompositeTypeScope;
import org.eclipse.cdt.core.dom.ast.c.ICFunctionScope;
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.AttributeUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
/**
* Collection of methods to find information in an AST.
*/
public class CVisitor extends ASTQueries {
private static final CBasicType UNSIGNED_LONG_INT = new CBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED);
public static class CollectProblemsAction extends ASTVisitor {
{
shouldVisitDeclarations = true;
shouldVisitExpressions = true;
shouldVisitStatements = true;
shouldVisitTypeIds = true;
}
private static final int DEFAULT_CHILDREN_LIST_SIZE = 8;
private IASTProblem[] problems = null;
int numFound = 0;
public CollectProblemsAction() {
problems = new IASTProblem[DEFAULT_CHILDREN_LIST_SIZE];
}
private void addProblem(IASTProblem problem) {
if (problems.length == numFound) { // if the found array is full, then double the array
IASTProblem[] old = problems;
problems = new IASTProblem[old.length * 2];
for (int j = 0; j < old.length; ++j)
problems[j] = old[j];
}
problems[numFound++] = problem;
}
private IASTProblem[] removeNullFromProblems() {
if (problems[problems.length - 1] != null) { // if the last element in the list is not null then return the list
return problems;
} else if (problems[0] == null) { // if the first element in the list is null, then return empty list
return new IASTProblem[0];
}
IASTProblem[] results = new IASTProblem[numFound];
for (int i=0; i<results.length; i++)
results[i] = problems[i];
return results;
}
public IASTProblem[] getProblems() {
return removeNullFromProblems();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processDeclaration(org.eclipse.cdt.core.dom.ast.IASTDeclaration)
*/
@Override
public int visit(IASTDeclaration declaration) {
if (declaration instanceof IASTProblemHolder)
addProblem(((IASTProblemHolder) declaration).getProblem());
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processExpression(org.eclipse.cdt.core.dom.ast.IASTExpression)
*/
@Override
public int visit(IASTExpression expression) {
if (expression instanceof IASTProblemHolder)
addProblem(((IASTProblemHolder) expression).getProblem());
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processStatement(org.eclipse.cdt.core.dom.ast.IASTStatement)
*/
@Override
public int visit(IASTStatement statement) {
if (statement instanceof IASTProblemHolder)
addProblem(((IASTProblemHolder) statement).getProblem());
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processTypeId(org.eclipse.cdt.core.dom.ast.IASTTypeId)
*/
@Override
public int visit(IASTTypeId typeId) {
if (typeId instanceof IASTProblemHolder)
addProblem(((IASTProblemHolder) typeId).getProblem());
return PROCESS_CONTINUE;
}
}
public static class CollectDeclarationsAction extends ASTVisitor {
{
shouldVisitDeclarators = true;
shouldVisitDeclSpecifiers = true;
shouldVisitEnumerators = true;
shouldVisitStatements = true;
}
private static final int DEFAULT_CHILDREN_LIST_SIZE = 8;
private IASTName[] declsFound = null;
int numFound = 0;
IBinding binding = null;
boolean compositeTypeDeclared = false;
private void addName(IASTName name) {
if (declsFound.length == numFound) { // if the found array is full, then double the array
IASTName[] old = declsFound;
declsFound = new IASTName[old.length * 2];
for (int j = 0; j < old.length; ++j)
declsFound[j] = old[j];
}
declsFound[numFound++] = name;
}
private IASTName[] removeNullFromNames() {
if (declsFound[declsFound.length - 1] != null) { // if the last element in the list is not null then return the list
return declsFound;
} else if (declsFound[0] == null) { // if the first element in the list is null, then return empty list
return new IASTName[0];
}
IASTName[] results = new IASTName[numFound];
for (int i= 0; i < results.length; i++)
results[i] = declsFound[i];
return results;
}
public IASTName[] getDeclarationNames() {
return removeNullFromNames();
}
public CollectDeclarationsAction(IBinding binding) {
declsFound = new IASTName[DEFAULT_CHILDREN_LIST_SIZE];
this.binding = binding;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processDeclarator(org.eclipse.cdt.core.dom.ast.IASTDeclarator)
*/
@Override
public int visit(IASTDeclarator declarator) {
//GCC allows declarations in expressions, so we have to continue from the
//declarator in case there is something in the initializer expression
if (declarator == null || declarator.getName() == null || declarator.getName().toCharArray().length == 0) return PROCESS_CONTINUE;
//if the binding is something not declared in a declarator, continue
if (binding instanceof ICompositeType)
return PROCESS_CONTINUE;
if (binding instanceof IEnumeration)
return PROCESS_CONTINUE;
IASTNode parent = declarator.getParent();
while (parent != null && !(parent instanceof IASTDeclaration || parent instanceof IASTParameterDeclaration))
parent = parent.getParent();
if (parent instanceof IASTDeclaration) {
if (parent instanceof IASTFunctionDefinition) {
if (declarator.getName() != null && declarator.getName().resolveBinding() == binding) {
addName(declarator.getName());
}
} else if (parent instanceof IASTSimpleDeclaration) {
// prototype parameter with no identifier isn't a declaration of the K&R C parameter
// if (binding instanceof CKnRParameter && declarator.getName().toCharArray().length == 0)
// return PROCESS_CONTINUE;
if ((declarator.getName() != null && declarator.getName().resolveBinding() == binding)) {
addName(declarator.getName());
}
}
} else if (parent instanceof IASTParameterDeclaration) {
if (declarator.getName() != null && declarator.getName().resolveBinding() == binding) {
addName(declarator.getName());
}
}
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processDeclSpecifier(org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier)
*/
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (compositeTypeDeclared && declSpec instanceof ICASTTypedefNameSpecifier)
return PROCESS_CONTINUE;
//if the binding isn't declared in a decl spec, skip it
if (!(binding instanceof ICompositeType) && !(binding instanceof IEnumeration))
return PROCESS_CONTINUE;
if (binding instanceof ICompositeType && declSpec instanceof IASTCompositeTypeSpecifier) {
if (((IASTCompositeTypeSpecifier) declSpec).getName().resolveBinding() == binding) {
compositeTypeDeclared = true;
addName(((IASTCompositeTypeSpecifier) declSpec).getName());
}
} else if (binding instanceof IEnumeration && declSpec instanceof IASTEnumerationSpecifier) {
if (((IASTEnumerationSpecifier) declSpec).getName().resolveBinding() == binding) {
compositeTypeDeclared = true;
addName(((IASTEnumerationSpecifier) declSpec).getName());
}
} else if (declSpec instanceof IASTElaboratedTypeSpecifier) {
if (compositeTypeDeclared) {
IASTNode parent = declSpec.getParent();
if (!(parent instanceof IASTSimpleDeclaration) || ((IASTSimpleDeclaration) parent).getDeclarators().length > 0) {
return PROCESS_CONTINUE;
}
}
if (((IASTElaboratedTypeSpecifier) declSpec).getName().resolveBinding() == binding) {
compositeTypeDeclared = true;
addName(((IASTElaboratedTypeSpecifier) declSpec).getName());
}
}
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processEnumerator(org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator)
*/
@Override
public int visit(IASTEnumerator enumerator) {
if (binding instanceof IEnumerator && enumerator.getName().resolveBinding() == binding) {
addName(enumerator.getName());
}
return PROCESS_CONTINUE;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.c.CVisitor.CBaseVisitorAction#processStatement(org.eclipse.cdt.core.dom.ast.IASTStatement)
*/
@Override
public int visit(IASTStatement statement) {
if (statement instanceof IASTLabelStatement && binding instanceof ILabel) {
if (((IASTLabelStatement) statement).getName().resolveBinding() == binding)
addName(((IASTLabelStatement) statement).getName());
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
}
public static class CollectReferencesAction extends ASTVisitor {
private static final int DEFAULT_LIST_SIZE = 8;
private IASTName[] refs;
private final IBinding binding;
private int idx = 0;
private int kind;
private static final int KIND_LABEL = 1;
private static final int KIND_OBJ_FN = 2;
private static final int KIND_TYPE = 3;
public CollectReferencesAction(IBinding binding) {
this.binding = binding;
this.refs = new IASTName[DEFAULT_LIST_SIZE];
shouldVisitNames = true;
if (binding instanceof ILabel) {
kind = KIND_LABEL;
} else if (binding instanceof ICompositeType ||
binding instanceof ITypedef ||
binding instanceof IEnumeration) {
kind = KIND_TYPE;
} else {
kind = KIND_OBJ_FN;
}
}
@Override
public int visit(IASTName name) {
ASTNodeProperty prop = name.getPropertyInParent();
switch (kind) {
case KIND_LABEL:
if (prop == IASTGotoStatement.NAME)
break;
return PROCESS_CONTINUE;
case KIND_TYPE:
if (prop == IASTNamedTypeSpecifier.NAME) {
break;
} else if (prop == IASTElaboratedTypeSpecifier.TYPE_NAME) {
IASTNode p = name.getParent().getParent();
if (!(p instanceof IASTSimpleDeclaration) ||
((IASTSimpleDeclaration) p).getDeclarators().length > 0) {
break;
}
}
return PROCESS_CONTINUE;
case KIND_OBJ_FN:
if (prop == IASTIdExpression.ID_NAME ||
prop == IASTFieldReference.FIELD_NAME ||
prop == ICASTFieldDesignator.FIELD_NAME) {
break;
}
return PROCESS_CONTINUE;
}
if (CharArrayUtils.equals(name.toCharArray(), binding.getNameCharArray())) {
if (sameBinding(name.resolveBinding(), binding)) {
if (refs.length == idx) {
IASTName[] temp = new IASTName[refs.length * 2];
System.arraycopy(refs, 0, temp, 0, refs.length);
refs = temp;
}
refs[idx++] = name;
}
}
return PROCESS_CONTINUE;
}
private boolean sameBinding(IBinding binding1, IBinding binding2) {
if (binding1 == binding2)
return true;
if (binding1 != null && binding1.equals(binding2))
return true;
return false;
}
public IASTName[] getReferences() {
if (idx < refs.length) {
IASTName[] temp = new IASTName[idx];
System.arraycopy(refs, 0, temp, 0, idx);
refs = temp;
}
return refs;
}
}
protected static final ASTNodeProperty STRING_LOOKUP_PROPERTY = new ASTNodeProperty("CVisitor.STRING_LOOKUP_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$
protected static final ASTNodeProperty STRING_LOOKUP_TAGS_PROPERTY = new ASTNodeProperty("CVisitor.STRING_LOOKUP_TAGS_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$
private static final String SIZE_T = "size_t"; //$NON-NLS-1$
private static final String PTRDIFF_T = "ptrdiff_t"; //$NON-NLS-1$
public static final String EMPTY_STRING = ""; //$NON-NLS-1$
// Definition lookup start location
protected static final int AT_BEGINNING = 1;
protected static final int AT_NEXT = 2;
static protected void createBinding(IASTName name) {
IBinding binding = null;
IASTNode parent = name.getParent();
if (parent instanceof CASTIdExpression) {
binding = resolveBinding(parent);
} else if (parent instanceof ICASTTypedefNameSpecifier) {
binding = resolveBinding(parent);
} else if (parent instanceof IASTFieldReference) {
binding = (IBinding) findBinding((IASTFieldReference) parent, false);
if (binding == null) {
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, name.toCharArray());
}
} else if (parent instanceof IASTDeclarator) {
binding = createBinding((IASTDeclarator) parent, name);
} else if (parent instanceof ICASTCompositeTypeSpecifier) {
binding = createBinding((ICASTCompositeTypeSpecifier) parent);
} else if (parent instanceof ICASTElaboratedTypeSpecifier) {
binding = createBinding((ICASTElaboratedTypeSpecifier) parent);
} else if (parent instanceof IASTStatement) {
binding = createBinding ((IASTStatement) parent);
} else if (parent instanceof ICASTEnumerationSpecifier) {
binding = createBinding((ICASTEnumerationSpecifier) parent);
} else if (parent instanceof IASTEnumerator) {
binding = createBinding((IASTEnumerator) parent);
} else if (parent instanceof ICASTFieldDesignator) {
binding = resolveBinding(parent);
}
name.setBinding(binding);
}
private static IBinding createBinding(ICASTEnumerationSpecifier enumeration) {
IASTName name = enumeration.getName();
IScope scope = getContainingScope(enumeration);
IBinding binding= null;
if (scope != null) {
binding = scope.getBinding(name, false);
}
if (binding != null && !(binding instanceof IIndexBinding) && name.isActive()) {
if (binding instanceof IEnumeration) {
if (binding instanceof CEnumeration) {
((CEnumeration) binding).addDefinition(name);
}
} else {
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD, name.toCharArray());
}
} else {
binding = new CEnumeration(name);
ASTInternal.addName(scope, name);
}
return binding;
}
private static IBinding createBinding(IASTEnumerator enumerator) {
IEnumerator binding = new CEnumerator(enumerator);
try {
ASTInternal.addName(binding.getScope(), enumerator.getName());
} catch (DOMException e) {
}
return binding;
}
private static IBinding createBinding(IASTStatement statement) {
if (statement instanceof IASTGotoStatement) {
char[] gotoName = ((IASTGotoStatement) statement).getName().toCharArray();
IScope scope = getContainingScope(statement);
if (scope != null && scope instanceof ICFunctionScope) {
CFunctionScope functionScope = (CFunctionScope) scope;
ILabel[] labels = functionScope.getLabels();
for (ILabel label : labels) {
if (CharArrayUtils.equals(label.getNameCharArray(), gotoName)) {
return label;
}
}
//label not found
return new ProblemBinding(((IASTGotoStatement) statement).getName(), IProblemBinding.SEMANTIC_LABEL_STATEMENT_NOT_FOUND, gotoName);
}
} else if (statement instanceof IASTLabelStatement) {
IASTName name = ((IASTLabelStatement) statement).getName();
IBinding binding = new CLabel(name);
try {
IScope scope = binding.getScope();
if (scope instanceof ICFunctionScope)
ASTInternal.addName(binding.getScope(), name);
} catch (DOMException e) {
}
return binding;
}
return null;
}
private static IBinding createBinding(ICASTElaboratedTypeSpecifier elabTypeSpec) {
IASTNode parent = elabTypeSpec.getParent();
IASTName name = elabTypeSpec.getName();
if (parent instanceof IASTDeclaration) {
IBinding binding= null;
IScope insertIntoScope= null;
if (parent instanceof IASTSimpleDeclaration
&& ((IASTSimpleDeclaration) parent).getDeclarators().length == 0) {
IScope scope= getContainingScope(elabTypeSpec);
try {
while (scope instanceof ICCompositeTypeScope)
scope= scope.getParent();
binding= scope.getBinding(name, false);
} catch (DOMException e) {
}
if (binding != null && name.isActive()) {
if (binding instanceof CEnumeration) {
((CEnumeration) binding).addDeclaration(name);
} else if (binding instanceof CStructure) {
((CStructure) binding).addDeclaration(name);
}
}
} else {
binding= resolveBinding(elabTypeSpec);
if (binding == null) {
insertIntoScope= elabTypeSpec.getTranslationUnit().getScope();
binding= insertIntoScope.getBinding(name, false);
if (binding != null && name.isActive()) {
if (binding instanceof CEnumeration) {
((CEnumeration) binding).addDeclaration(name);
} else if (binding instanceof CStructure) {
((CStructure) binding).addDeclaration(name);
}
}
}
}
if (binding == null) {
if (elabTypeSpec.getKind() == IASTElaboratedTypeSpecifier.k_enum) {
binding = new CEnumeration(name);
} else {
binding = new CStructure(name);
}
if (insertIntoScope != null) {
ASTInternal.addName(insertIntoScope, name);
}
}
return binding;
} else if (parent instanceof IASTTypeId || parent instanceof IASTParameterDeclaration) {
return resolveBinding(elabTypeSpec);
}
return null;
}
/**
* if prefix == false, return an IBinding or null
* if prefix == true, return an IBinding[] or null
* @param fieldReference
* @param prefix
* @return
*/
private static Object findBinding(IASTFieldReference fieldReference, boolean prefix) {
IASTExpression fieldOwner = fieldReference.getFieldOwner();
if (fieldOwner == null)
return null;
IType type = fieldOwner.getExpressionType();
while (type != null && type instanceof ITypeContainer) {
type = ((ITypeContainer) type).getType();
}
if (type != null && type instanceof ICompositeType) {
ICompositeType ct = (ICompositeType) type;
if (ct instanceof IIndexBinding) {
ct= ((CASTTranslationUnit) fieldReference.getTranslationUnit()).mapToASTType(ct);
}
if (prefix) {
char[] p = fieldReference.getFieldName().toCharArray();
return findFieldsByPrefix(ct, p);
}
return ct.findField(fieldReference.getFieldName().toString());
}
return null;
}
public static IBinding[] findFieldsByPrefix(final ICompositeType ct, char[] p) {
IBinding[] result = null;
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(p);
IField[] fields = ct.getFields();
for (IField field : fields) {
if (matcher.match(field.getNameCharArray())) {
result = ArrayUtil.append(IBinding.class, result, field);
}
}
return ArrayUtil.trim(IBinding.class, result);
}
static IType getPtrDiffType(IASTBinaryExpression expr) {
IScope scope = getContainingScope(expr);
IBinding[] bs = scope.find(PTRDIFF_T);
for (IBinding b : bs) {
if (b instanceof IType) {
if (!(b instanceof ICInternalBinding) ||
CVisitor.declaredBefore(((ICInternalBinding) b).getPhysicalNode(), expr)) {
return (IType) b;
}
}
}
return new CBasicType(Kind.eInt, 0, expr);
}
static IType get_SIZE_T(IASTExpression expr) {
IASTTranslationUnit tu= expr.getTranslationUnit();
if (tu != null) {
IBinding[] bs = tu.getScope().find(SIZE_T);
for (IBinding b : bs) {
if (b instanceof IType) {
if (!(b instanceof ICInternalBinding) ||
CVisitor.declaredBefore(((ICInternalBinding) b).getPhysicalNode(), expr)) {
return (IType) b;
}
}
}
}
return UNSIGNED_LONG_INT;
}
static IType unwrapTypedefs(IType type) {
while (type instanceof ITypedef) {
type= ((ITypedef) type).getType();
}
return type;
}
/**
* @param parent
* @return
*/
private static IBinding createBinding(IASTDeclarator declarator, IASTName name) {
IBinding binding = null;
if (declarator instanceof ICASTKnRFunctionDeclarator) {
if (CharArrayUtils.equals(declarator.getName().toCharArray(), name.toCharArray())) {
IScope scope= CVisitor.getContainingScope(declarator);
binding = scope.getBinding(name, false);
if (binding != null && !(binding instanceof IIndexBinding) && name.isActive()) {
if (binding instanceof ICInternalFunction) {
((ICInternalFunction) binding).addDeclarator(declarator);
} else {
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD, name.toCharArray());
}
} else {
binding = createBinding(declarator);
}
} else { // createBinding for one of the ICASTKnRFunctionDeclarator's parameterNames
IBinding f = declarator.getName().resolveBinding();
if (f instanceof CFunction) {
binding = ((CFunction) f).resolveParameter(name);
}
}
} else {
binding = createBinding(declarator);
}
return binding;
}
private static IBinding createBinding(IASTDeclarator declarator) {
IASTNode parent = ASTQueries.findOutermostDeclarator(declarator).getParent();
declarator= ASTQueries.findInnermostDeclarator(declarator);
IASTDeclarator typeRelevant= ASTQueries.findTypeRelevantDeclarator(declarator);
IScope scope= getContainingScope(parent);
ASTNodeProperty prop = parent.getPropertyInParent();
if (prop == IASTDeclarationStatement.DECLARATION) {
//implicit scope, see 6.8.4-3
prop = parent.getParent().getPropertyInParent();
if (prop != IASTCompoundStatement.NESTED_STATEMENT)
scope = null;
}
IASTName name = declarator.getName();
IBinding binding = (scope != null) ? scope.getBinding(name, false) : null;
boolean isFunction= false;
if (parent instanceof IASTParameterDeclaration || parent.getPropertyInParent() == ICASTKnRFunctionDeclarator.FUNCTION_PARAMETER) {
IASTDeclarator fdtor = (IASTDeclarator) parent.getParent();
if (ASTQueries.findTypeRelevantDeclarator(fdtor) instanceof IASTFunctionDeclarator) {
IASTName n= ASTQueries.findInnermostDeclarator(fdtor).getName();
IBinding temp = n.resolveBinding();
if (temp != null && temp instanceof CFunction) {
binding = ((CFunction) temp).resolveParameter(name);
} else if (temp instanceof IFunction) {
//problems with the function, still create binding for the parameter
binding = new CParameter(name);
}
return binding;
}
} else if (parent instanceof IASTFunctionDefinition) {
isFunction= true;
} else if (parent instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent;
if (simpleDecl.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef) {
binding = new CTypedef(name);
} else {
isFunction= typeRelevant instanceof IASTFunctionDeclarator;
if (!isFunction) {
IType t1 = createType(declarator), t2 = null;
if (CVisitor.unwrapTypedefs(t1) instanceof IFunctionType) {
isFunction= true;
} else {
if (binding != null && !(binding instanceof IIndexBinding) && name.isActive()) {
if (binding instanceof IParameter) {
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION, name.toCharArray());
} else if (binding instanceof IVariable) {
t2 = ((IVariable) binding).getType();
if (t1 != null && t2 != null && (
t1.isSameType(t2) || isCompatibleArray(t1, t2) != null)) {
if (binding instanceof CVariable)
((CVariable) binding).addDeclaration(name);
} else {
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION, name.toCharArray());
}
}
} else if (simpleDecl.getParent() instanceof ICASTCompositeTypeSpecifier) {
binding = new CField(name);
} else {
binding = new CVariable(name);
}
}
}
}
}
if (isFunction) {
if (binding != null && !(binding instanceof IIndexBinding) && name.isActive()) {
if (binding instanceof IFunction) {
IFunction function = (IFunction) binding;
if (function instanceof CFunction) {
((CFunction) function).addDeclarator(typeRelevant);
}
return function;
}
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD, name.toCharArray());
} else {
binding = new CFunction(typeRelevant);
}
}
return binding;
}
private static IBinding createBinding(ICASTCompositeTypeSpecifier compositeTypeSpec) {
IScope scope = null;
IBinding binding = null;
IASTName name = compositeTypeSpec.getName();
try {
scope = getContainingScope(compositeTypeSpec);
while (scope instanceof ICCompositeTypeScope)
scope = scope.getParent();
if (scope != null) {
binding = scope.getBinding(name, false);
if (binding != null && !(binding instanceof IIndexBinding) && name.isActive()) {
if (binding instanceof CStructure)
((CStructure) binding).addDefinition(compositeTypeSpec);
return binding;
}
}
} catch (DOMException e) {
}
return new CStructure(name);
}
protected static IBinding resolveBinding(IASTNode node) {
if (node instanceof IASTFunctionDefinition) {
IASTFunctionDefinition functionDef = (IASTFunctionDefinition) node;
IASTFunctionDeclarator functionDeclartor = functionDef.getDeclarator();
IASTName name = findInnermostDeclarator(functionDeclartor).getName();
IScope scope = getContainingScope(node);
return lookup(scope, name);
} else if (node instanceof IASTIdExpression) {
IScope scope = getContainingScope(node);
IBinding binding = lookup(scope, ((IASTIdExpression) node).getName());
if (binding instanceof IType && !(binding instanceof IProblemBinding) ) {
return new ProblemBinding(node, IProblemBinding.SEMANTIC_INVALID_TYPE,
binding.getNameCharArray(), new IBinding[] { binding });
}
return binding;
} else if (node instanceof ICASTTypedefNameSpecifier) {
IScope scope = getContainingScope(node);
IASTName name= ((ICASTTypedefNameSpecifier) node).getName();
IBinding binding = lookup(scope, name);
if (binding == null)
return new ProblemBinding(node, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, name.toCharArray());
if (binding instanceof IType)
return binding;
return new ProblemBinding(node, IProblemBinding.SEMANTIC_INVALID_TYPE, binding.getNameCharArray(),
new IBinding[] { binding });
} else if (node instanceof ICASTElaboratedTypeSpecifier) {
IScope scope = getContainingScope(node);
return lookup(scope, ((ICASTElaboratedTypeSpecifier) node).getName());
} else if (node instanceof ICASTCompositeTypeSpecifier) {
IScope scope = getContainingScope(node);
return lookup(scope, ((ICASTCompositeTypeSpecifier) node).getName());
} else if (node instanceof IASTTypeId) {
IASTTypeId typeId = (IASTTypeId) node;
IASTDeclSpecifier declSpec = typeId.getDeclSpecifier();
IASTName name = null;
if (declSpec instanceof ICASTElaboratedTypeSpecifier) {
name = ((ICASTElaboratedTypeSpecifier) declSpec).getName();
} else if (declSpec instanceof ICASTCompositeTypeSpecifier) {
name = ((ICASTCompositeTypeSpecifier) declSpec).getName();
} else if (declSpec instanceof ICASTTypedefNameSpecifier) {
name = ((ICASTTypedefNameSpecifier) declSpec).getName();
}
if (name != null) {
IBinding binding = name.resolveBinding();
if (binding instanceof IType) {
return binding;
} else if (binding != null) {
return new ProblemBinding(node, IProblemBinding.SEMANTIC_INVALID_TYPE,
binding.getNameCharArray(), new IBinding[] { binding });
}
return null;
}
} else if (node instanceof ICASTFieldDesignator) {
IASTNode blockItem = getContainingBlockItem(node);
if ((blockItem instanceof IASTSimpleDeclaration ||
(blockItem instanceof IASTDeclarationStatement && ((IASTDeclarationStatement) blockItem).getDeclaration() instanceof IASTSimpleDeclaration))) {
IASTSimpleDeclaration simpleDecl = null;
if (blockItem instanceof IASTDeclarationStatement &&
((IASTDeclarationStatement) blockItem).getDeclaration() instanceof IASTSimpleDeclaration) {
simpleDecl = (IASTSimpleDeclaration)((IASTDeclarationStatement) blockItem).getDeclaration();
} else if (blockItem instanceof IASTSimpleDeclaration) {
simpleDecl = (IASTSimpleDeclaration) blockItem;
}
if (simpleDecl != null) {
IBinding struct = null;
if (simpleDecl.getDeclSpecifier() instanceof IASTNamedTypeSpecifier)
struct = ((IASTNamedTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
else if (simpleDecl.getDeclSpecifier() instanceof IASTElaboratedTypeSpecifier)
struct = ((IASTElaboratedTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
else if (simpleDecl.getDeclSpecifier() instanceof IASTCompositeTypeSpecifier)
struct = ((IASTCompositeTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
if (struct instanceof ICompositeType) {
return ((ICompositeType) struct).findField(((ICASTFieldDesignator) node).getName().toString());
} else if (struct instanceof ITypeContainer) {
IType type;
type = ((ITypeContainer) struct).getType();
while (type instanceof ITypeContainer && !(type instanceof CStructure)) {
type = ((ITypeContainer) type).getType();
}
if (type instanceof CStructure)
return ((CStructure) type).findField(((ICASTFieldDesignator) node).getName().toString());
}
}
}
}
return null;
}
/**
* May return <code>null</code>, e.g. for parameter names in function-prototypes.
*/
public static IScope getContainingScope(IASTNode node) {
if (node == null)
return null;
while (node != null) {
if (node instanceof IASTDeclaration) {
IASTNode parent = node.getParent();
if (parent instanceof IASTTranslationUnit) {
return ((IASTTranslationUnit) parent).getScope();
} else if (parent instanceof IASTDeclarationStatement) {
return getContainingScope((IASTStatement) parent);
} else if (parent instanceof IASTForStatement) {
return ((IASTForStatement) parent).getScope();
} else if (parent instanceof IASTCompositeTypeSpecifier) {
return ((IASTCompositeTypeSpecifier) parent).getScope();
} else if (parent instanceof ICASTKnRFunctionDeclarator) {
parent = ((IASTDeclarator) parent).getParent();
if (parent instanceof IASTFunctionDefinition) {
return ((IASTCompoundStatement)((IASTFunctionDefinition) parent).getBody()).getScope();
}
}
} else if (node instanceof IASTStatement) {
return getContainingScope((IASTStatement) node);
} else if (node instanceof IASTExpression) {
IASTNode parent = node.getParent();
if (parent instanceof IASTForStatement) {
return ((IASTForStatement) parent).getScope();
}
} else if (node instanceof IASTParameterDeclaration) {
IASTNode parent = node.getParent();
if (parent instanceof IASTStandardFunctionDeclarator) {
IASTStandardFunctionDeclarator dtor = (IASTStandardFunctionDeclarator) parent;
if (ASTQueries.findTypeRelevantDeclarator(dtor) == dtor) {
parent= ASTQueries.findOutermostDeclarator(dtor);
ASTNodeProperty prop = parent.getPropertyInParent();
if (prop == IASTSimpleDeclaration.DECLARATOR)
return dtor.getFunctionScope();
else if (prop == IASTFunctionDefinition.DECLARATOR)
return ((IASTCompoundStatement) ((IASTFunctionDefinition) parent.getParent()).getBody()).getScope();
}
}
} else if (node instanceof IASTEnumerator) {
//put the enumerators in the same scope as the enumeration
node = node.getParent();
} else if (node instanceof IASTName) {
ASTNodeProperty prop = node.getPropertyInParent();
if (prop == IASTLabelStatement.NAME) {
IScope scope= getContainingScope(node.getParent());
//labels have function scope
while (scope != null && !(scope instanceof ICFunctionScope)) {
try {
scope = scope.getParent();
} catch (DOMException e) {
scope = e.getProblem();
break;
}
}
return scope;
}
}
node = node.getParent();
}
return null;
}
public static IScope getContainingScope(IASTStatement statement) {
IASTNode parent = statement.getParent();
IScope scope = null;
if (parent instanceof IASTCompoundStatement) {
IASTCompoundStatement compound = (IASTCompoundStatement) parent;
scope = compound.getScope();
} else if (parent instanceof IASTStatement) {
if (parent instanceof IASTForStatement) {
scope= ((IASTForStatement) parent).getScope();
} else {
scope = getContainingScope((IASTStatement) parent);
}
} else if (parent instanceof IASTFunctionDefinition) {
return ((IASTFunctionDefinition) parent).getScope();
} else {
return getContainingScope(parent);
}
if (statement instanceof IASTGotoStatement) {
// labels have function scope
while (scope != null && !(scope instanceof ICFunctionScope)) {
try {
scope = scope.getParent();
} catch (DOMException e) {
scope = e.getProblem();
break;
}
}
}
return scope;
}
private static IASTNode getContainingBlockItem(IASTNode node) {
IASTNode parent = node.getParent();
if (parent instanceof IASTDeclaration) {
IASTNode p = parent.getParent();
if (p instanceof IASTDeclarationStatement)
return p;
return parent;
} else if (parent instanceof IASTCompoundStatement || // parent is something that can contain a declaration
parent instanceof IASTTranslationUnit ||
parent instanceof IASTForStatement ||
parent instanceof IASTFunctionDeclarator) {
return node;
}
return getContainingBlockItem(parent);
}
/**
* Lookup for a name starting from the given scope.
*/
protected static IBinding lookup(IScope scope, IASTName name) {
if (scope == null)
return null;
IIndexFileSet fileSet= IIndexFileSet.EMPTY;
IASTTranslationUnit tu= name.getTranslationUnit();
if (tu == null && scope instanceof IASTInternalScope) {
tu= ((IASTInternalScope) scope).getPhysicalNode().getTranslationUnit();
}
if (tu != null) {
final IIndexFileSet fs= (IIndexFileSet) tu.getAdapter(IIndexFileSet.class);
if (fs != null) {
fileSet= fs;
}
}
while (scope != null) {
if (!(scope instanceof ICCompositeTypeScope)) {
IBinding binding = scope.getBinding(name, true, fileSet);
if (binding != null)
return binding;
}
try {
scope= scope.getParent();
} catch (DOMException e) {
scope= null;
}
}
return externalBinding(tu, name);
}
/**
* if (bits & PREFIX_LOOKUP) then returns IBinding[]
* otherwise returns IBinding
*/
protected static IBinding[] lookupPrefix(IScope scope, IASTName name) throws DOMException{
if (scope == null)
return null;
IBinding[] result = null;
CharArraySet handled= new CharArraySet(1);
while (scope != null) {
if (!(scope instanceof ICCompositeTypeScope)) {
IBinding[] bindings= scope.getBindings(new ScopeLookupData(name, true, true));
for (IBinding b : bindings) {
final char[] n= b.getNameCharArray();
// consider binding only if no binding with the same name was found in another scope.
if (!handled.containsKey(n)) {
result= ArrayUtil.append(IBinding.class, result, b);
}
}
// store names of bindings
for (IBinding b : bindings) {
final char[] n= b.getNameCharArray();
handled.put(n);
}
}
scope= scope.getParent();
}
return ArrayUtil.trim(IBinding.class, result);
}
private static IBinding externalBinding(IASTTranslationUnit tu, IASTName name) {
IASTNode parent = name.getParent();
IBinding external = null;
if (parent instanceof IASTIdExpression) {
if (parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
//external function
external = new CExternalFunction(tu, name);
ASTInternal.addName(tu.getScope(), name);
} else {
//external variable
//external = new CExternalVariable(tu, name);
//((CScope) tu.getScope()).addName(name);
external = new ProblemBinding(name, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, name.toCharArray());
}
}
return external;
}
protected static IASTDeclarator findDefinition(IASTDeclarator declarator, int beginAtLoc) {
return (IASTDeclarator) findDefinition(declarator, declarator.getName().toCharArray(), beginAtLoc);
}
protected static IASTFunctionDeclarator findDefinition(IASTFunctionDeclarator declarator) {
return (IASTFunctionDeclarator) findDefinition(declarator, declarator.getName().toCharArray(), AT_NEXT);
}
protected static IASTDeclSpecifier findDefinition(ICASTElaboratedTypeSpecifier declSpec) {
return (IASTDeclSpecifier) findDefinition(declSpec, declSpec.getName().toCharArray(), AT_BEGINNING);
}
private static IASTNode findDefinition(IASTNode decl, char[] declName, int beginAtLoc) {
IASTNode blockItem = getContainingBlockItem(decl);
IASTNode parent = blockItem.getParent();
IASTNode[] list = null;
if (parent instanceof IASTCompoundStatement) {
IASTCompoundStatement compound = (IASTCompoundStatement) parent;
list = compound.getStatements();
} else if (parent instanceof IASTTranslationUnit) {
IASTTranslationUnit translation = (IASTTranslationUnit) parent;
list = translation.getDeclarations();
}
boolean begun = (beginAtLoc == AT_BEGINNING);
if (list != null) {
for (IASTNode node : list) {
if (node == blockItem) {
begun = true;
continue;
}
if (begun) {
if (node instanceof IASTDeclarationStatement) {
node = ((IASTDeclarationStatement) node).getDeclaration();
}
if (node instanceof IASTFunctionDefinition && decl instanceof IASTFunctionDeclarator) {
IASTFunctionDeclarator dtor = ((IASTFunctionDefinition) node).getDeclarator();
IASTName name = ASTQueries.findInnermostDeclarator(dtor).getName();
if (name.toString().equals(declName)) {
return dtor;
}
} else if (node instanceof IASTSimpleDeclaration && decl instanceof ICASTElaboratedTypeSpecifier) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) node;
IASTDeclSpecifier declSpec = simpleDecl.getDeclSpecifier();
IASTName name = null;
if (declSpec instanceof ICASTCompositeTypeSpecifier) {
name = ((ICASTCompositeTypeSpecifier) declSpec).getName();
} else if (declSpec instanceof ICASTEnumerationSpecifier) {
name = ((ICASTEnumerationSpecifier) declSpec).getName();
}
if (name != null) {
if (CharArrayUtils.equals(name.toCharArray(), declName)) {
return declSpec;
}
}
} else if (node instanceof IASTSimpleDeclaration && decl instanceof IASTDeclarator) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) node;
IASTDeclarator[] dtors = simpleDecl.getDeclarators();
for (int j = 0; dtors != null && j < dtors.length; j++) {
if (CharArrayUtils.equals(dtors[j].getName().toCharArray(), declName)) {
return dtors[j];
}
}
}
}
}
}
return null;
}
/**
* Create an IType for an IASTDeclarator.
*
* @param declarator the IASTDeclarator whose IType will be created
* @return the IType of the IASTDeclarator parameter
*/
public static IType createType(IASTDeclarator declarator) {
IASTDeclSpecifier declSpec = null;
IASTNode node = declarator.getParent();
while (node instanceof IASTDeclarator) {
declarator = (IASTDeclarator) node;
node = node.getParent();
}
if (node instanceof IASTSimpleDeclaration) {
declSpec = ((IASTSimpleDeclaration) node).getDeclSpecifier();
} else if (node instanceof IASTParameterDeclaration) {
declSpec = ((IASTParameterDeclaration) node).getDeclSpecifier();
} else if (node instanceof IASTFunctionDefinition) {
declSpec = ((IASTFunctionDefinition) node).getDeclSpecifier();
} else if (node instanceof IASTTypeId) {
declSpec = ((IASTTypeId) node).getDeclSpecifier();
}
boolean isParameter = (node instanceof IASTParameterDeclaration || node.getParent() instanceof ICASTKnRFunctionDeclarator);
IType type = createType((ICASTDeclSpecifier) declSpec);
type = createType(type, declarator);
if (isParameter) {
IType paramType = type;
// Remove typedefs ready for subsequent processing.
while (paramType instanceof ITypedef) {
paramType = ((ITypedef) paramType).getType();
}
//C99: 6.7.5.3-7 a declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the
//type qualifiers (if any) are those specified within the[and] of the array type derivation
if (paramType instanceof IArrayType) { // the index does not yet return ICArrayTypes
IArrayType at = (IArrayType) paramType;
int q= 0;
if (at instanceof ICArrayType) {
ICArrayType cat= (ICArrayType) at;
if (cat.isConst()) q |= CPointerType.IS_CONST;
if (cat.isVolatile()) q |= CPointerType.IS_VOLATILE;
if (cat.isRestrict()) q |= CPointerType.IS_RESTRICT;
}
type = new CPointerType(at.getType(), q);
} else if (paramType instanceof IFunctionType) {
//-8 A declaration of a parameter as "function returning type" shall be adjusted to "pointer to function returning type"
type = new CPointerType(paramType, 0);
}
}
return type;
}
public static IType createType(IType baseType, IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator)
return createType(baseType, (IASTFunctionDeclarator) declarator);
IType type = baseType;
type = applyAttributes(type, declarator);
type = setupPointerChain(declarator.getPointerOperators(), type);
type = setupArrayChain(declarator, type);
IASTDeclarator nested = declarator.getNestedDeclarator();
if (nested != null) {
return createType(type, nested);
}
return type;
}
private static IType applyAttributes(IType type, IASTDeclarator declarator) {
if (type instanceof IBasicType) {
IBasicType basicType = (IBasicType) type;
if (basicType.getKind() == IBasicType.Kind.eInt) {
IASTAttribute[] attributes = declarator.getAttributes();
for (IASTAttribute attribute : attributes) {
char[] name = attribute.getName();
if (CharArrayUtils.equals(name, "__mode__") || CharArrayUtils.equals(name, "mode")) { //$NON-NLS-1$ //$NON-NLS-2$
char[] mode = AttributeUtil.getSimpleArgument(attribute);
if (CharArrayUtils.equals(mode, "__QI__") || CharArrayUtils.equals(mode, "QI")) { //$NON-NLS-1$ //$NON-NLS-2$
type = new CBasicType(IBasicType.Kind.eChar,
basicType.isUnsigned() ? IBasicType.IS_UNSIGNED : IBasicType.IS_SIGNED);
} else if (CharArrayUtils.equals(mode, "__HI__") || CharArrayUtils.equals(mode, "HI")) { //$NON-NLS-1$ //$NON-NLS-2$
type = new CBasicType(IBasicType.Kind.eInt,
IBasicType.IS_SHORT | getSignModifiers(basicType));
} else if (CharArrayUtils.equals(mode, "__SI__") || CharArrayUtils.equals(mode, "SI")) { //$NON-NLS-1$ //$NON-NLS-2$
type = new CBasicType(IBasicType.Kind.eInt, getSignModifiers(basicType));
} else if (CharArrayUtils.equals(mode, "__DI__") || CharArrayUtils.equals(mode, "DI")) { //$NON-NLS-1$ //$NON-NLS-2$
SizeofCalculator sizeofs = new SizeofCalculator(declarator.getTranslationUnit());
int modifier;
if (sizeofs.sizeof_long != null && sizeofs.sizeof_int != null &&
sizeofs.sizeof_long.size == 2 * sizeofs.sizeof_int.size) {
modifier = IBasicType.IS_LONG;
} else {
modifier = IBasicType.IS_LONG_LONG;
}
type = new CBasicType(IBasicType.Kind.eInt,
modifier | getSignModifiers(basicType));
} else if (CharArrayUtils.equals(mode, "__word__") || CharArrayUtils.equals(mode, "word")) { //$NON-NLS-1$ //$NON-NLS-2$
type = new CBasicType(IBasicType.Kind.eInt,
IBasicType.IS_LONG | getSignModifiers(basicType));
}
}
}
}
}
return type;
}
private static int getSignModifiers(IBasicType type) {
return type.getModifiers() & (IBasicType.IS_SIGNED | IBasicType.IS_UNSIGNED);
}
public static IType createType(IType returnType, IASTFunctionDeclarator declarator) {
IType[] pTypes = getParmTypes(declarator);
returnType = setupPointerChain(declarator.getPointerOperators(), returnType);
IType type = new CFunctionType(returnType, pTypes);
IASTDeclarator nested = declarator.getNestedDeclarator();
if (nested != null) {
return createType(type, nested);
}
return type;
}
/**
* This is used to create a base IType corresponding to an IASTDeclarator and
* the IASTDeclSpecifier. This method doesn't have any recursive behavior and is used as
* the foundation of the ITypes being created. The parameter isParm is used to specify whether
* the declarator is a parameter or not.
*
* @param declSpec the IASTDeclSpecifier used to determine if the base type is a CQualifierType
* or not
* @return the base IType
*/
public static IType createBaseType(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICASTSimpleDeclSpecifier) {
final ICASTSimpleDeclSpecifier sds = (ICASTSimpleDeclSpecifier) declSpec;
IASTExpression exp = sds.getDeclTypeExpression();
if (exp != null)
return exp.getExpressionType();
return new CBasicType(sds);
}
IBinding binding = null;
IASTName name = null;
if (declSpec instanceof ICASTTypedefNameSpecifier) {
name = ((ICASTTypedefNameSpecifier) declSpec).getName();
} else if (declSpec instanceof IASTElaboratedTypeSpecifier) {
name = ((IASTElaboratedTypeSpecifier) declSpec).getName();
} else if (declSpec instanceof IASTCompositeTypeSpecifier) {
name = ((IASTCompositeTypeSpecifier) declSpec).getName();
} else if (declSpec instanceof IASTEnumerationSpecifier) {
name = ((IASTEnumerationSpecifier) declSpec).getName();
} else {
throw new IllegalArgumentException();
}
if (name == null)
return new ProblemType(ISemanticProblem.TYPE_NO_NAME);
binding = name.resolveBinding();
if (binding instanceof IType && !(binding instanceof IProblemBinding))
return (IType) binding;
return new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
}
public static IType createType(ICASTDeclSpecifier declSpec) {
if (declSpec.isConst() || declSpec.isVolatile() || declSpec.isRestrict()) {
return new CQualifierType(declSpec);
}
return createBaseType(declSpec);
}
/**
* Returns an IType[] corresponding to the parameter types of the IASTFunctionDeclarator parameter.
*
* @param decltor the IASTFunctionDeclarator to create an IType[] for its parameters
* @return IType[] corresponding to the IASTFunctionDeclarator parameters
*/
private static IType[] getParmTypes(IASTFunctionDeclarator decltor) {
if (decltor instanceof IASTStandardFunctionDeclarator) {
IASTParameterDeclaration parms[] = ((IASTStandardFunctionDeclarator) decltor).getParameters();
IType parmTypes[] = new IType[parms.length];
for (int i = 0; i < parms.length; i++) {
parmTypes[i] = createType(parms[i].getDeclarator());
}
return parmTypes;
} else if (decltor instanceof ICASTKnRFunctionDeclarator) {
IASTName parms[] = ((ICASTKnRFunctionDeclarator) decltor).getParameterNames();
IType parmTypes[] = new IType[parms.length];
for (int i = 0; i < parms.length; i++) {
IASTDeclarator dtor = getKnRParameterDeclarator((ICASTKnRFunctionDeclarator) decltor, parms[i]);
if (dtor != null)
parmTypes[i] = createType(dtor);
}
return parmTypes;
} else {
throw new IllegalArgumentException();
}
}
protected static IASTDeclarator getKnRParameterDeclarator(ICASTKnRFunctionDeclarator fKnRDtor, IASTName name) {
IASTDeclaration[] decls = fKnRDtor.getParameterDeclarations();
char[] n = name.toCharArray();
for (int i = 0; i < decls.length; i++) {
if (!(decls[i] instanceof IASTSimpleDeclaration))
continue;
IASTDeclarator[] dtors = ((IASTSimpleDeclaration) decls[i]).getDeclarators();
for (IASTDeclarator dtor : dtors) {
if (CharArrayUtils.equals(dtor.getName().toCharArray(), n)) {
return dtor;
}
}
}
return null;
}
/**
* Traverse through an array of IASTArrayModifier[] corresponding to the IASTDeclarator decl parameter.
* For each IASTArrayModifier in the array, create a corresponding CArrayType object and
* link it in a chain. The returned IType is the start of the CArrayType chain that represents
* the types of the IASTArrayModifier objects in the declarator.
*
* @param decl the IASTDeclarator containing the IASTArrayModifier[] array to create a CArrayType chain for
* @param lastType the IType that the end of the CArrayType chain points to
* @return the starting CArrayType at the beginning of the CArrayType chain
*/
private static IType setupArrayChain(IASTDeclarator decl, IType lastType) {
if (decl instanceof IASTArrayDeclarator) {
IASTArrayModifier[] mods = ((IASTArrayDeclarator) decl).getArrayModifiers();
for (int i = mods.length - 1; i >= 0; i--) {
CArrayType arrayType = new CArrayType(lastType);
if (mods[i] instanceof ICASTArrayModifier) {
arrayType.setModifier((ICASTArrayModifier) mods[i]);
}
lastType= arrayType;
}
}
return lastType;
}
/**
* Traverse through an array of IASTPointerOperator[] pointers and set up a pointer chain
* corresponding to the types of the IASTPointerOperator[].
*
* @param ptrs an array of IASTPointerOperator[] used to setup the pointer chain
* @param lastType the IType that the end of the CPointerType chain points to
* @return the starting CPointerType at the beginning of the CPointerType chain
*/
private static IType setupPointerChain(IASTPointerOperator[] ptrs, IType lastType) {
CPointerType pointerType = null;
if (ptrs != null && ptrs.length > 0) {
pointerType = new CPointerType();
if (ptrs.length == 1) {
pointerType.setType(lastType);
pointerType.setQualifiers(
(((ICASTPointer) ptrs[0]).isConst() ? CPointerType.IS_CONST : 0) |
(((ICASTPointer) ptrs[0]).isRestrict() ? CPointerType.IS_RESTRICT : 0) |
(((ICASTPointer) ptrs[0]).isVolatile() ? CPointerType.IS_VOLATILE : 0));
} else {
CPointerType tempType = new CPointerType();
pointerType.setType(tempType);
pointerType.setQualifiers(
(((ICASTPointer) ptrs[ptrs.length - 1]).isConst() ? CPointerType.IS_CONST : 0) |
(((ICASTPointer) ptrs[ptrs.length - 1]).isRestrict() ? CPointerType.IS_RESTRICT : 0) |
(((ICASTPointer) ptrs[ptrs.length - 1]).isVolatile() ? CPointerType.IS_VOLATILE : 0));
int i = ptrs.length - 2;
for (; i > 0; i--) {
tempType.setType(new CPointerType());
tempType.setQualifiers(
(((ICASTPointer) ptrs[i]).isConst() ? CPointerType.IS_CONST : 0) |
(((ICASTPointer) ptrs[i]).isRestrict() ? CPointerType.IS_RESTRICT : 0) |
(((ICASTPointer) ptrs[i]).isVolatile() ? CPointerType.IS_VOLATILE : 0));
tempType = (CPointerType) tempType.getType();
}
tempType.setType(lastType);
tempType.setQualifiers(
(((ICASTPointer) ptrs[i]).isConst() ? CPointerType.IS_CONST : 0) |
(((ICASTPointer) ptrs[i]).isRestrict() ? CPointerType.IS_RESTRICT : 0) |
(((ICASTPointer) ptrs[i]).isVolatile() ? CPointerType.IS_VOLATILE : 0));
}
return pointerType;
}
return lastType;
}
public static IASTProblem[] getProblems(IASTTranslationUnit tu) {
CollectProblemsAction action = new CollectProblemsAction();
tu.accept(action);
return action.getProblems();
}
public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding) {
CollectDeclarationsAction action = new CollectDeclarationsAction(binding);
tu.accept(action);
return action.getDeclarationNames();
}
public static IASTName[] getReferences(IASTTranslationUnit tu, IBinding binding) {
CollectReferencesAction action = new CollectReferencesAction(binding);
tu.accept(action);
return action.getReferences();
}
public static IBinding[] findBindingsForContentAssist(IASTName name, boolean isPrefix) {
ASTNodeProperty prop = name.getPropertyInParent();
IBinding[] result = null;
if (prop == IASTFieldReference.FIELD_NAME) {
result = (IBinding[]) findBinding((IASTFieldReference) name.getParent(), isPrefix);
} else if (prop == ICASTFieldDesignator.FIELD_NAME) {
result = findBindingForContentAssist((ICASTFieldDesignator) name.getParent(), isPrefix);
} else {
IScope scope= getContainingScope(name);
try {
if (isPrefix) {
result = lookupPrefix(scope, name);
} else {
result = new IBinding[] { lookup(scope, name) };
}
} catch (DOMException e) {
}
}
return ArrayUtil.trim(IBinding.class, result);
}
private static IBinding[] findBindingForContentAssist(ICASTFieldDesignator fd, boolean isPrefix) {
IASTNode blockItem = getContainingBlockItem(fd);
IASTNode parent= blockItem;
while (parent != null && !(parent instanceof IASTSimpleDeclaration))
parent= parent.getParent();
if (parent instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent;
IBinding struct= null;
if (simpleDecl.getDeclSpecifier() instanceof IASTNamedTypeSpecifier) {
struct = ((IASTNamedTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
} else if (simpleDecl.getDeclSpecifier() instanceof IASTElaboratedTypeSpecifier) {
struct = ((IASTElaboratedTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
} else if (simpleDecl.getDeclSpecifier() instanceof IASTCompositeTypeSpecifier) {
struct = ((IASTCompositeTypeSpecifier) simpleDecl.getDeclSpecifier()).getName().resolveBinding();
}
if (struct instanceof IType) {
IType t= unwrapTypedefs((IType) struct);
if (t instanceof ICompositeType) {
return findFieldsByPrefix((ICompositeType) t, fd.getName().toCharArray());
}
}
}
return null;
}
public static IBinding[] findBindings(IScope scope, String name) {
CASTName astName = new CASTName(name.toCharArray());
// normal names
astName.setPropertyInParent(STRING_LOOKUP_PROPERTY);
Object o1 = lookup(scope, astName);
IBinding[] b1 = null;
if (o1 instanceof IBinding) {
b1 = new IBinding[] { (IBinding) o1 };
} else {
b1 = (IBinding[]) o1;
}
// structure names
astName.setPropertyInParent(STRING_LOOKUP_TAGS_PROPERTY);
Object o2 = lookup(scope, astName);
IBinding[] b2 = null;
if (o2 instanceof IBinding) {
b2 = new IBinding[] { (IBinding) o2 };
} else {
b2 = (IBinding[]) o2;
}
// label names
List<ILabel> b3 = new ArrayList<ILabel>();
do {
char[] n = name.toCharArray();
if (scope instanceof ICFunctionScope) {
ILabel[] labels = ((CFunctionScope) scope).getLabels();
for (ILabel label : labels) {
if (CharArrayUtils.equals(label.getNameCharArray(), n)) {
b3.add(label);
break;
}
}
break;
}
try {
scope = scope.getParent();
} catch (DOMException e) {
scope= null;
}
} while (scope != null);
int c = (b1 == null ? 0 : b1.length) + (b2 == null ? 0 : b2.length) + b3.size();
IBinding[] result = new IBinding[c];
if (b1 != null)
ArrayUtil.addAll(IBinding.class, result, b1);
if (b2 != null)
ArrayUtil.addAll(IBinding.class, result, b2);
ArrayUtil.addAll(IBinding.class, result, b3.toArray(new IBinding[b3.size()]));
return result;
}
static public boolean declaredBefore(IASTNode nodeA, IASTNode nodeB) {
if (nodeB == null) return true;
if (nodeB.getPropertyInParent() == STRING_LOOKUP_PROPERTY) return true;
if (nodeA instanceof ASTNode) {
ASTNode nd= (ASTNode) nodeA;
int pointOfDecl = 0;
ASTNodeProperty prop = nd.getPropertyInParent();
// point of declaration for a name is immediately after its complete declarator and before its initializer
if (prop == IASTDeclarator.DECLARATOR_NAME || nd instanceof IASTDeclarator) {
IASTDeclarator dtor = (IASTDeclarator)((nd instanceof IASTDeclarator) ? nd : nd.getParent());
while (dtor.getParent() instanceof IASTDeclarator)
dtor = (IASTDeclarator) dtor.getParent();
IASTInitializer init = dtor.getInitializer();
if (init != null)
pointOfDecl = ((ASTNode) init).getOffset() - 1;
else
pointOfDecl = ((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength();
}
// point of declaration for an enumerator is immediately after it enumerator-definition
else if (prop == IASTEnumerator.ENUMERATOR_NAME) {
IASTEnumerator enumtor = (IASTEnumerator) nd.getParent();
if (enumtor.getValue() != null) {
ASTNode exp = (ASTNode) enumtor.getValue();
pointOfDecl = exp.getOffset() + exp.getLength();
} else {
pointOfDecl = nd.getOffset() + nd.getLength();
}
} else {
pointOfDecl = nd.getOffset() + nd.getLength();
}
return pointOfDecl < ((ASTNode) nodeB).getOffset();
}
return true;
}
/**
* Searches for the function enclosing the given node. May return <code>null</code>.
*/
public static IBinding findEnclosingFunction(IASTNode node) {
while (node != null && !(node instanceof IASTFunctionDefinition)) {
node= node.getParent();
}
if (node == null)
return null;
IASTDeclarator dtor= findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator());
if (dtor != null) {
IASTName name= dtor.getName();
if (name != null) {
return name.resolveBinding();
}
}
return null;
}
/**
* Searches for the first function, struct or union enclosing the declaration the provided
* node belongs to and returns the binding for it. Returns <code>null</code>, if the declaration is not
* enclosed by any of the above constructs.
*/
public static IBinding findDeclarationOwner(IASTNode node, boolean allowFunction) {
// search for declaration
while (!(node instanceof IASTDeclaration)) {
if (node == null)
return null;
node= node.getParent();
}
// search for enclosing binding
IASTName name= null;
node= node.getParent();
for (; node != null; node= node.getParent()) {
if (node instanceof IASTFunctionDefinition) {
if (!allowFunction)
continue;
IASTDeclarator dtor= findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator());
if (dtor != null) {
name= dtor.getName();
}
break;
}
if (node instanceof IASTCompositeTypeSpecifier) {
name= ((IASTCompositeTypeSpecifier) node).getName();
break;
}
}
if (name == null)
return null;
return name.resolveBinding();
}
}