/******************************************************************************* * Copyright (c) 2005, 2016 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) * Marc-Andre Laperle (Ericsson) * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ 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.IASTCastExpression; 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.IASTUnaryExpression; 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.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IQualifierType; 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.IValue; 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.dom.parser.ValueFactory; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; 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 IASTGotoStatement) { binding = resolveBinding((IASTGotoStatement) parent); } else if (parent instanceof IASTLabelStatement) { binding = createBinding((IASTLabelStatement) 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 resolveBinding(IASTGotoStatement statement) { return resolveLabel(statement.getName()); } private static IBinding createBinding(IASTLabelStatement statement) { IASTName name = 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; } 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, expr.getTranslationUnit()); 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, IBasicType.IS_LONG, expr); } static IType get_SIZE_T(IASTExpression expr) { IASTTranslationUnit tu= expr.getTranslationUnit(); if (tu != null) { IBinding[] bs = tu.getScope().find(SIZE_T, expr.getTranslationUnit()); 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; } static IType unwrapCV(IType type) { while (type instanceof IQualifierType) { type = ((IQualifierType) type).getType(); } if (type instanceof IPointerType) { type = new CPointerType(((IPointerType) type).getType(), 0 /* no qualifiers */); } 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(); // Create parameter bindings only if the declarator declares a function if (ASTQueries.findTypeRelevantDeclarator(fdtor) == fdtor) { 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 && (areArraysOfTheSameElementType(t1, t2) || t1.isSameType(t2))) { 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) { if (isLabelReference(node)) { return resolveLabel(((IASTIdExpression) node).getName()); } 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) { for (IASTNode parent = node.getParent(); parent != null; parent = parent.getParent()) { if (parent instanceof IASTDeclaration) { IASTNode p = parent.getParent(); if (p instanceof IASTDeclarationStatement) return p; return parent; } if (parent instanceof IASTCompoundStatement || // parent is something that can contain a declaration parent instanceof IASTTranslationUnit || parent instanceof IASTForStatement || parent instanceof IASTFunctionDeclarator) { return node; } node = parent; } return null; } /** * 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= 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; } private static IType createType(IASTTypeId typeId) { return createType(typeId.getAbstractDeclarator()); } 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); boolean takesVarargs = declarator instanceof IASTStandardFunctionDeclarator && ((IASTStandardFunctionDeclarator) declarator).takesVarArgs(); IType type = new CFunctionType(returnType, pTypes, takesVarargs); 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()); } if (parmTypes.length == 1 && SemanticUtil.isVoidType(parmTypes[0])) return IType.EMPTY_TYPE_ARRAY; // f(void) is the same as f() 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 declarationNode = blockItem; if (blockItem instanceof IASTDeclarationStatement && ((IASTDeclarationStatement) blockItem).getDeclaration() instanceof IASTSimpleDeclaration) { declarationNode = ((IASTDeclarationStatement) blockItem).getDeclaration(); } else { while (declarationNode != null && !(declarationNode instanceof IASTSimpleDeclaration)) declarationNode= declarationNode.getParent(); } if (declarationNode instanceof IASTSimpleDeclaration) { IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) declarationNode; 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<>(); do { char[] n = name.toCharArray(); if (scope instanceof CFunctionScope) { IASTFunctionDefinition def = ASTQueries.findAncestorWithType( ((CFunctionScope) scope).getPhysicalNode(), IASTFunctionDefinition.class); ILabel[] labels = getLabels(def); 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 (nodeB.getPropertyInParent() == STRING_LOOKUP_TAGS_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 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(); } /** * Determine whether an expression is a null pointer constant. */ public static boolean isNullPointerConstant(IASTExpression expression) { // [6.3.2.3] p3: An integer constant expression with the value 0, or such an expression cast // to void*, is called a null pointer constant. // Unwrap extra parentheses. if (expression instanceof IASTUnaryExpression) { IASTUnaryExpression unaryExpression = (IASTUnaryExpression) expression; if (unaryExpression.getOperator() == IASTUnaryExpression.op_bracketedPrimary) { return isNullPointerConstant(unaryExpression.getOperand()); } } if (expression instanceof IASTCastExpression) { IASTCastExpression castExpression = (IASTCastExpression) expression; IType castType = createType(castExpression.getTypeId()); if (castType.isSameType(CPointerType.VOID_POINTER)) { return isNullPointerConstant(castExpression.getOperand()); } } IType expressionType = expression.getExpressionType(); if (expressionType instanceof IBasicType) { IValue value = ValueFactory.create(expression); if (value != null && value.numberValue() != null) { return value.numberValue().longValue() == 0; } } return false; } }