/******************************************************************************* * Copyright (c) 2004, 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 Corporation) - initial API and implementation * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) * Thomas Corbat (IFS) * Nathan Ridge * Marc-Andre Laperle * Anders Dahlberg (Ericsson) - bug 84144 *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor; 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.EScopeKind; 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.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; 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.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTInitializerList; 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.IASTPointer; 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.IASTSimpleDeclSpecifier; 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.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.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.IQualifierType; import org.eclipse.cdt.core.dom.ast.IScope; 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.cpp.ICPPASTAliasDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPointerToMember; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeTransformationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeferredFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.AttributeUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; 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.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionCallExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTUnaryExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerator; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPField; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLabel; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLambdaExpressionParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceAlias; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedef; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownTypeScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluationOwner; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; /** * Collection of methods to extract information from a C++ translation unit. */ public class CPPVisitor extends ASTQueries { public static final String BEGIN_STR = "begin"; //$NON-NLS-1$ public static final char[] BEGIN = BEGIN_STR.toCharArray(); public static final char[] END = "end".toCharArray(); //$NON-NLS-1$ public static final String STD = "std"; //$NON-NLS-1$ private static final char[] SIZE_T = "size_t".toCharArray(); //$NON-NLS-1$ private static final char[] PTRDIFF_T = "ptrdiff_t".toCharArray(); //$NON-NLS-1$ private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$ private static final char[] INITIALIZER_LIST = "initializer_list".toCharArray(); //$NON-NLS-1$ private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {}; public static final IASTInitializerClause[] NO_ARGS = {}; // Thread-local set of DeclSpecifiers for which auto types are being created. // Used to prevent infinite recursion while processing invalid self-referencing // auto-type declarations. private static final ThreadLocal<Set<IASTDeclSpecifier>> autoTypeDeclSpecs = new ThreadLocal<Set<IASTDeclSpecifier>>() { @Override protected Set<IASTDeclSpecifier> initialValue() { return new HashSet<>(); } }; public static IBinding createBinding(IASTName name) { IASTNode parent = name.getParent(); IBinding binding = null; if (parent instanceof IASTNamedTypeSpecifier || parent instanceof ICPPASTBaseSpecifier || parent instanceof ICPPASTConstructorChainInitializer || parent instanceof ICPPASTCapture || name.getPropertyInParent() == ICPPASTNamespaceAlias.MAPPING_NAME) { if (name.getLookupKey().length == 0) return null; return CPPSemantics.resolveBinding(name); } else if (parent instanceof ICPPASTQualifiedName) { if (name.getLookupKey().length == 0) return null; final ICPPASTQualifiedName qname = (ICPPASTQualifiedName) parent; if (name != qname.getLastName()) return CPPSemantics.resolveBinding(name); parent = parent.getParent(); if (!declaresMemberInClassOrNamespace(qname)) { binding = CPPSemantics.resolveBinding(name); if (parent instanceof IASTCompositeTypeSpecifier) { if (binding instanceof IIndexBinding) { // Need to create an AST binding. } else { ASTInternal.addDefinition(binding, parent); return binding; } } else { return binding; } } } else if (parent instanceof ICPPASTTemplateId) { final ICPPASTTemplateId id = (ICPPASTTemplateId) parent; if (CPPTemplates.isClassTemplate(id)) return CPPSemantics.resolveBinding(name); // Function templates/instances/specializations must be resolved via the id. id.resolveBinding(); return name.getBinding(); } if (parent instanceof IASTIdExpression) { return resolveBinding(parent); } else if (parent instanceof ICPPASTFieldReference) { return resolveBinding(parent); } else if (parent instanceof ICPPASTCompositeTypeSpecifier) { return createBinding((ICPPASTCompositeTypeSpecifier) parent); } else if (parent instanceof IASTDeclarator) { return createBinding((IASTDeclarator) parent); } else if (parent instanceof ICPPASTElaboratedTypeSpecifier) { return createBinding((ICPPASTElaboratedTypeSpecifier) parent); } else if (parent instanceof IASTDeclaration) { return createBinding((IASTDeclaration) parent); } else if (parent instanceof ICPPASTEnumerationSpecifier) { return createBinding((ICPPASTEnumerationSpecifier) parent); } else if (parent instanceof IASTEnumerator) { return createBinding((IASTEnumerator) parent); } else if (parent instanceof IASTGotoStatement) { return resolveBinding((IASTGotoStatement) parent); } else if (parent instanceof IASTLabelStatement) { return createBinding((IASTLabelStatement) parent); } else if (parent instanceof ICPPASTTemplateParameter) { return CPPTemplates.createBinding((ICPPASTTemplateParameter) parent); } else if (parent instanceof ICPPASTFieldDesignator) { binding = resolveBinding(parent); } if (name.getLookupKey().length > 0) return binding; return null; } private static boolean declaresMemberInClassOrNamespace(ICPPASTQualifiedName qname) { ICPPASTNameSpecifier[] qualifier= qname.getQualifier(); if (qualifier.length == 0) return false; IASTNode parent= qname.getParent(); IASTNode decl= null; if (parent instanceof IASTCompositeTypeSpecifier) { decl= parent.getParent(); } else if (parent instanceof IASTDeclarator) { decl= ASTQueries.findOutermostDeclarator((IASTDeclarator) parent).getParent(); } IScope inScope= null; while (decl != null) { ASTNodeProperty prop = decl.getPropertyInParent(); if (prop == IASTCompositeTypeSpecifier.MEMBER_DECLARATION) { inScope = ((ICPPASTCompositeTypeSpecifier) decl.getParent()).getScope(); break; } else if (prop == ICPPASTNamespaceDefinition.OWNED_DECLARATION) { inScope = ((ICPPASTNamespaceDefinition) decl.getParent()).getScope(); break; } else if (prop == ICPPASTTemplateDeclaration.OWNED_DECLARATION) { decl= decl.getParent(); } else { return false; } } if (inScope == null) return false; IBinding pb= qualifier[qualifier.length - 1].resolvePreBinding(); if (pb instanceof IProblemBinding) return false; IScope scope= null; if (pb instanceof IType) { IType t= SemanticUtil.getNestedType((IType) pb, TDEF); if (t instanceof ICPPClassType) { scope= ((ICPPClassType) t).getCompositeScope(); } } else if (pb instanceof ICPPNamespace) { scope= ((ICPPNamespace) pb).getNamespaceScope(); } return scope == inScope; } private static IBinding resolveBinding(IASTGotoStatement gotoStatement) { return resolveLabel(gotoStatement.getName()); } private static IBinding createBinding(IASTLabelStatement labelStatement) { IASTName name = labelStatement.getName(); ICPPFunctionScope functionScope = (ICPPFunctionScope) getContainingScope(name); IBinding binding = functionScope.getBinding(name, false); if (binding == null || !(binding instanceof ILabel)) { binding = new CPPLabel(name); ASTInternal.addName(functionScope, name); } else { ((CPPLabel) binding).setLabelStatement(name); } return binding; } private static IBinding createBinding(IASTEnumerator enumerator) { ICPPScope scope = (ICPPScope) getContainingScope(enumerator); IBinding enumtor; enumtor = scope.getBinding(enumerator.getName(), false); if (enumtor == null || !(enumtor instanceof IEnumerator)) { enumtor = new CPPEnumerator(enumerator.getName()); } return enumtor; } private static IBinding createBinding(ICPPASTEnumerationSpecifier specifier) { ICPPScope scope = (ICPPScope) getContainingScope(specifier); final IASTName name = specifier.getName(); IType fixedType= createEnumBaseType(specifier); IBinding binding = scope.getBinding(name, false); if (binding instanceof CPPEnumeration) { CPPEnumeration e= (CPPEnumeration) binding; if (name.equals(e.getDefinition())) { return e; } if (e.isScoped() == specifier.isScoped()) { IType ft2= e.getFixedType(); if (fixedType == ft2 || (fixedType != null && fixedType.isSameType(ft2))) { if (specifier.isOpaque()) { e.addDeclaration(name); } else if (e.getDefinition() == null) { e.addDefinition(name); } else { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); } return e; } } return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } // [dcl.enum] 7.2-5 // "The underlying type can be explicitly specified using enum-base; // if not explicitly specified, the underlying type of a scoped // enumeration type is int." if (fixedType == null && specifier.isScoped()) { fixedType = CPPBasicType.INT; } return new CPPEnumeration(specifier, fixedType); } private static IType createEnumBaseType(ICPPASTEnumerationSpecifier specifier) { ICPPASTDeclSpecifier declspec = specifier.getBaseType(); if (declspec != null) { IType type= createType(declspec); return SemanticUtil.getNestedType(type, ALLCVQ); } if (specifier.isScoped()) { return CPPSemantics.INT_TYPE; } return null; } private static IBinding createBinding(final ICPPASTElaboratedTypeSpecifier elabType) { final IASTNode parent = elabType.getParent(); IBinding binding = null; boolean mustBeSimple = true; boolean isFriend = false; boolean qualified = false; IASTName name = elabType.getName(); if (name instanceof ICPPASTQualifiedName) { qualified = true; name = name.getLastName(); } if (parent instanceof IASTSimpleDeclaration) { IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) parent; ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier(); IASTDeclarator[] dtors = simpleDeclaration.getDeclarators(); isFriend = declSpec.isFriend() && dtors.length == 0; if (dtors.length != 0 || isFriend) { binding = CPPSemantics.resolveBinding(name); mustBeSimple = !isFriend; } else { mustBeSimple = false; } } else if (parent instanceof IASTParameterDeclaration || parent instanceof IASTDeclaration || parent instanceof IASTTypeId) { binding = CPPSemantics.resolveBinding(elabType.getName()); } if (binding instanceof IIndexBinding && binding instanceof ICPPClassType) { binding= (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding, elabType); ASTInternal.addDeclaration(binding, elabType); } if (binding != null && (!(binding instanceof IProblemBinding) || ((IProblemBinding) binding).getID() != IProblemBinding.SEMANTIC_NAME_NOT_FOUND)) { return binding; } // 7.1.5.3-2 ... If name lookup does not find a declaration for the name, the elaborated-type-specifier is ill-formed // unless it is of the simple form class-key identifier if (mustBeSimple && (elabType.getName() instanceof ICPPASTQualifiedName || elabType.getKind() == IASTElaboratedTypeSpecifier.k_enum)) { return binding; } try { ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); ICPPScope scope = (ICPPScope) getContainingScope(name); while (scope instanceof ICPPTemplateScope) { scope= (ICPPScope) scope.getParent(); } if (mustBeSimple) { // 3.3.1-5 ... the identifier is declared in the smallest non-class non-function-prototype // scope that contains the declaration. while (scope instanceof ICPPClassScope || scope instanceof ICPPFunctionScope) { scope = CPPSemantics.getParentScope(scope, elabType.getTranslationUnit()); } } if (scope instanceof ICPPClassScope && isFriend && !qualified) { while (scope instanceof ICPPClassScope) { scope = CPPSemantics.getParentScope(scope, elabType.getTranslationUnit()); } } if (scope != null) { binding = scope.getBinding(elabType.getName(), false); if (binding instanceof ICPPUsingDeclaration) { IBinding[] expanded = ((ICPPUsingDeclaration) binding).getDelegates(); if (expanded.length == 1 && expanded[0] instanceof IType) { binding= expanded[0]; } } } if (binding instanceof ICPPInternalBinding) { if (!name.isActive()) return binding; if (binding instanceof ICPPClassType) { ICPPInternalBinding internalBinding = (ICPPInternalBinding) binding; if (templateParametersMatch((ICPPClassType) binding, templateDecl)) { internalBinding.addDeclaration(elabType); return binding; } if (CPPSemantics.declaredBefore(internalBinding, name, false)) { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } markRedeclaration(internalBinding); } } // Create a binding. if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) { if (templateDecl != null) { binding = new CPPClassTemplate(name); } else { binding = new CPPClassType(name, binding); } // Name may live in a different scope, so make sure to add it to the owner scope as well. ASTInternal.addName(scope, elabType.getName()); } } catch (DOMException e) { binding = e.getProblem(); } return binding; } /** * Checks if the given name is the name of a friend declaration. * * @param name the name to check * @return {@code true} if {@code name} is the name of a friend declaration */ public static boolean isNameOfFriendDeclaration(IASTNode name) { if (name.getPropertyInParent() == ICPPASTQualifiedName.SEGMENT_NAME) { ICPPASTQualifiedName qName = (ICPPASTQualifiedName) name.getParent(); if (name != qName.getLastName()) return false; name = qName; } if (name.getPropertyInParent() != ICPPASTElaboratedTypeSpecifier.TYPE_NAME) return false; ICPPASTElaboratedTypeSpecifier typeSpec = (ICPPASTElaboratedTypeSpecifier) name.getParent(); if (typeSpec.getPropertyInParent() != IASTSimpleDeclaration.DECL_SPECIFIER) return false; IASTSimpleDeclaration declaration = (IASTSimpleDeclaration) typeSpec.getParent(); ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) declaration.getDeclSpecifier(); return declSpec.isFriend() && declaration.getDeclarators().length == 0; } public static void markRedeclaration(final ICPPInternalBinding ib) { // Mark the other declarations as problem and create the binding final IASTNode[] decls = ib.getDeclarations(); if (decls != null) { for (IASTNode decl : decls) { if (decl instanceof IASTName) { final IASTName n = (IASTName) decl; n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); } } } IASTNode decl= ib.getDefinition(); if (decl instanceof IASTName) { final IASTName n = (IASTName) decl; n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); } } /** * Tests whether a class binding matches the template parameters of another declaration */ private static boolean templateParametersMatch(ICPPClassType binding, ICPPASTTemplateDeclaration templateDecl) { final boolean isTemplate= binding instanceof ICPPClassTemplate; if (templateDecl == null) return !isTemplate; if (!isTemplate) return false; ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters(); ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters(); int i=0; for (ICPPASTTemplateParameter p2 : pars2) { if (i >= pars1.length) return true; if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2)) return false; } return true; } private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) { IASTName name = compType.getName().getLastName(); if (name instanceof ICPPASTTemplateId) return CPPTemplates.createBinding((ICPPASTTemplateId) name); ICPPScope scope = (ICPPScope) getContainingScope(name); try { while (scope instanceof ICPPTemplateScope) { scope= (ICPPScope) scope.getParent(); } } catch (DOMException e) { return e.getProblem(); } // Can't lookup anonymous names. IBinding binding= null; ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); if (name.getLookupKey().length > 0 && scope != null) { binding = scope.getBinding(name, false); if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) { ICPPInternalBinding internalBinding = (ICPPInternalBinding) binding; if (internalBinding.getDefinition() == null && templateParametersMatch((ICPPClassType) binding, templateDecl)) { ASTInternal.addDefinition(internalBinding, compType); return binding; } if (CPPSemantics.declaredBefore(internalBinding, name, false)) { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); } markRedeclaration(internalBinding); } } if (templateDecl != null) return new CPPClassTemplate(name); return new CPPClassType(name, binding); } private static IBinding createBinding(IASTDeclaration declaration) { if (declaration instanceof ICPPASTNamespaceDefinition) { ICPPASTNamespaceDefinition namespaceDef = (ICPPASTNamespaceDefinition) declaration; ICPPScope scope = (ICPPScope) getContainingScope(namespaceDef); IBinding binding; binding = scope.getBinding(namespaceDef.getName(), false); if (!(binding instanceof ICPPInternalBinding) || binding instanceof IProblemBinding || !(binding instanceof ICPPNamespace)) { binding = new CPPNamespace(namespaceDef); } return binding; } else if (declaration instanceof ICPPASTUsingDirective) { return CPPSemantics.resolveBinding(((ICPPASTUsingDirective) declaration).getQualifiedName()); } else if (declaration instanceof ICPPASTNamespaceAlias) { ICPPASTNamespaceAlias alias = (ICPPASTNamespaceAlias) declaration; ICPPScope scope = (ICPPScope) getContainingScope(declaration); IBinding binding; binding = scope.getBinding(alias.getAlias(), false); if (!(binding instanceof ICPPInternalBinding)) { IBinding namespace = alias.getMappingName().resolveBinding(); if (namespace instanceof IProblemBinding) { IProblemBinding problem = (IProblemBinding) namespace; namespace = new CPPNamespace.CPPNamespaceProblem(problem.getASTNode(), problem.getID(), alias.getMappingName().toCharArray()); } if (namespace instanceof ICPPNamespace) { binding = new CPPNamespaceAlias(alias.getAlias(), (ICPPNamespace) namespace); } else { binding = new ProblemBinding(alias.getAlias(), IProblemBinding.SEMANTIC_NAME_NOT_FOUND); } } return binding; } else if (declaration instanceof ICPPASTAliasDeclaration) { ICPPASTAliasDeclaration alias = (ICPPASTAliasDeclaration) declaration; ICPPScope scope = (ICPPScope) getContainingScope(declaration); IBinding binding = scope.getBinding(alias.getAlias(), false); if (!(binding instanceof ICPPInternalBinding)) { IType type = createType(alias.getMappingTypeId()); if (type instanceof IProblemBinding) { IProblemBinding problem = (IProblemBinding) type; type = new CPPClassType.CPPClassTypeProblem(problem.getASTNode(), problem.getID(), alias.getMappingTypeId().getAbstractDeclarator().getName().toCharArray()); } if (type != null) { if (alias.getParent() instanceof ICPPASTTemplateDeclaration) { binding = new CPPAliasTemplate(alias.getAlias(), type); } else { CPPTypedef typedef = new CPPTypedef(alias.getAlias()); typedef.setType(type); binding = typedef; } } else { binding = new ProblemBinding(alias.getAlias(), IProblemBinding.SEMANTIC_NAME_NOT_FOUND); } } return binding; } return null; } private static IBinding createBinding(IASTDeclarator declarator) { IASTNode parent = findOutermostDeclarator(declarator).getParent(); declarator= findInnermostDeclarator(declarator); final IASTDeclarator typeRelevantDtor= findTypeRelevantDeclarator(declarator); IASTName name= declarator.getName().getLastName(); // In case the binding was created starting from another name within the declarator. IBinding candidate= name.getBinding(); if (candidate != null) { return candidate; } // Function type. if (parent instanceof IASTTypeId) return CPPSemantics.resolveBinding(name); // Function type for non-type template parameter. ASTNodeProperty prop = parent.getPropertyInParent(); if (prop == ICPPASTTemplateDeclaration.PARAMETER || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER) { return CPPTemplates.createBinding((ICPPASTTemplateParameter) parent); } // Explicit instantiations. if (prop == ICPPASTExplicitTemplateInstantiation.OWNED_DECLARATION) return CPPSemantics.resolveBinding(name); // Explicit specializations. ICPPASTTemplateDeclaration tmplDecl= CPPTemplates.getTemplateDeclaration(name); if (tmplDecl instanceof ICPPASTTemplateSpecialization) { IBinding b= CPPSemantics.resolveBinding(name); if (parent instanceof ICPPASTFunctionDefinition) { ASTInternal.addDefinition(b, name); } else { ASTInternal.addDeclaration(b, name); } return b; } // Parameter declarations. if (parent instanceof ICPPASTParameterDeclaration) { ICPPASTParameterDeclaration param = (ICPPASTParameterDeclaration) parent; parent = param.getParent(); if (parent instanceof IASTStandardFunctionDeclarator) { IASTStandardFunctionDeclarator fdtor = (IASTStandardFunctionDeclarator) param.getParent(); // Create parameter bindings only if the declarator declares a function. if (findTypeRelevantDeclarator(fdtor) != fdtor) return null; final IASTNode dtorParent= findOutermostDeclarator(fdtor).getParent(); if (dtorParent instanceof ICPPASTLambdaExpression) { return new CPPLambdaExpressionParameter(name); } if (dtorParent instanceof IASTDeclaration) { IASTParameterDeclaration[] params = fdtor.getParameters(); int i= 0; for (; i < params.length; i++) { if (params[i] == param) break; } return new CPPParameter(name, i); } return null; } else if (parent instanceof ICPPASTTemplateDeclaration) { return CPPTemplates.createBinding(param); } return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_TYPE); } // Function declaration/definition. IBinding binding= null; final boolean template= tmplDecl != null; boolean isFriendDecl= false; ICPPScope scope = (ICPPScope) getContainingNonTemplateScope(name); if (scope instanceof ICPPClassScope) { isFriendDecl = isFriendDeclaration(parent); if (isFriendDecl) { try { while (scope.getKind() == EScopeKind.eClassType) { scope = CPPSemantics.getParentScope(scope, name.getTranslationUnit()); } } catch (DOMException e1) { } } } boolean forceResolve= isFriendDecl && name instanceof ICPPASTTemplateId; if (name.getLookupKey().length != 0 && scope != null) { binding = scope.getBinding(name, forceResolve); } boolean isFunction= false; if (parent instanceof ICPPASTFunctionDefinition) { isFunction= true; } else if (parent instanceof IASTSimpleDeclaration) { IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent; if (simpleDecl.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef) { // Typedef declaration. if (binding instanceof ICPPInternalBinding && binding instanceof ITypedef && name.isActive()) { IType t1 = ((ITypedef) binding).getType(); IType t2 = createType(declarator); if (t1 != null && t2 != null && t1.isSameType(t2)) { ASTInternal.addDeclaration(binding, name); return binding; } return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } // If we don't resolve the target type first, we get a problem binding in case // the typedef redeclares the target type, otherwise it is safer to defer // the resolution of the target type. IType targetType= createType(declarator); CPPTypedef td= new CPPTypedef(name); td.setType(targetType); binding = td; } else if (typeRelevantDtor instanceof IASTFunctionDeclarator) { // Function declaration via function declarator. isFunction= true; } else { // Looks like a variable declaration. IType t1 = createType(declarator); if (SemanticUtil.getNestedType(t1, TDEF) instanceof IFunctionType) { // Function declaration via a typedef for a function type isFunction= true; } else if (binding instanceof IParameter) { // Variable declaration redeclaring a parameter. binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } else { // Variable declaration. IType t2= null; if (binding != null && binding instanceof IVariable && !(binding instanceof IIndexBinding)) { t2 = ((IVariable) binding).getType(); } if (t1 != null && t2 != null) { if (areArraysOfTheSameElementType(t1, t2) || t1.isSameType(t2)) { ASTInternal.addDeclaration(binding, name); } else { binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } } else if (simpleDecl.getParent() instanceof ICPPASTCompositeTypeSpecifier) { binding = new CPPField(name); } else if (template) { if (simpleDecl.getParent().getParent() instanceof ICPPASTCompositeTypeSpecifier) { binding = new CPPFieldTemplate(name); } else { binding = new CPPVariableTemplate(name); } } else { binding = new CPPVariable(name); } } } } if (isFunction) { if (binding instanceof ICPPInternalBinding && binding instanceof ICPPFunction && name.isActive()) { ICPPFunction function = (ICPPFunction) binding; boolean sameFunction = CPPSemantics.isSameFunction(function, typeRelevantDtor) || function instanceof ICPPDeferredFunction; if (function.getOwner() instanceof ICPPClassType) { // Don't consider a function brought into scope from a base class scope // to be the same as a function declared in a derived class scope. IScope bindingScope = ((ICPPClassType) function.getOwner()).getCompositeScope(); if (bindingScope == null || !bindingScope.equals(scope)) { sameFunction = false; } } if (sameFunction) { binding= CPPSemantics.checkDeclSpecifier(binding, name, parent); if (binding instanceof IProblemBinding) return binding; ICPPInternalBinding internal = (ICPPInternalBinding) function; if (parent instanceof IASTSimpleDeclaration) { ASTInternal.addDeclaration(internal, name); } else if (internal.getDefinition() == null) { ASTInternal.addDefinition(internal, name); } else { IASTNode def = internal.getDefinition(); if (def instanceof IASTDeclarator) def = ((IASTDeclarator) def).getName(); if (def != name) { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); } } return function; } } if (scope instanceof ICPPClassScope) { if (isConstructor(scope, typeRelevantDtor)) { binding = template ? (ICPPConstructor) new CPPConstructorTemplate(name) : new CPPConstructor((ICPPASTFunctionDeclarator) typeRelevantDtor); } else { binding = template ? (ICPPMethod) new CPPMethodTemplate(name) : new CPPMethod(typeRelevantDtor); } } else { binding = template ? (ICPPFunction) new CPPFunctionTemplate(name) : new CPPFunction(typeRelevantDtor); } binding= CPPSemantics.checkDeclSpecifier(binding, name, parent); if (isFriendDecl && scope instanceof IASTInternalScope) { ((IASTInternalScope) scope).addBinding(binding); } } return binding; } public static boolean isFriendDeclaration(IASTNode decl) { IASTDeclSpecifier declSpec; if (decl instanceof IASTSimpleDeclaration) { declSpec = ((IASTSimpleDeclaration) decl).getDeclSpecifier(); } else if (decl instanceof IASTFunctionDefinition) { declSpec = ((IASTFunctionDefinition) decl).getDeclSpecifier(); } else { return false; } return declSpec instanceof ICPPASTDeclSpecifier && ((ICPPASTDeclSpecifier) declSpec).isFriend(); } public static boolean isConstructor(IScope containingScope, IASTDeclarator declarator) { if (containingScope instanceof ICPPClassScope && isConstructorDtor(declarator)) { ICPPClassType classType= ((ICPPClassScope) containingScope).getClassType(); final char[] dtorName = findInnermostDeclarator(declarator).getName().getLookupKey(); return CharArrayUtils.equals(dtorName, classType.getNameCharArray()); } return false; } public static boolean isConstructorDeclaration(IASTName name) { if (name == null) return false; final ASTNodeProperty propertyInParent = name.getPropertyInParent(); if (propertyInParent == null) return false; IASTNode parent = name.getParent(); if (parent instanceof ICPPASTTemplateId) { name= (IASTName) parent; parent= name.getParent(); } if (parent instanceof ICPPASTQualifiedName) { if (((ICPPASTQualifiedName) parent).getLastName() != name) return false; name= (IASTName) parent; parent= name.getParent(); } if (parent instanceof IASTDeclarator) { if (isConstructorDtor((IASTDeclarator) parent)) { if (name instanceof ICPPASTQualifiedName) { ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) name).getQualifier(); if (qualifier.length >= 1) { IBinding b= qualifier[qualifier.length - 1].resolvePreBinding(); if (b instanceof IType) { IType classType= getNestedType((IType) b, TDEF); if (classType instanceof ICPPClassType) { final char[] dtorName = name.getLastName().getLookupKey(); final char[] className = ((ICPPClassType) classType).getNameCharArray(); return CharArrayUtils.equals(dtorName, className); } } } return false; } while (parent != null) { if (parent instanceof ICPPASTCompositeTypeSpecifier) { final char[] className= ((ICPPASTCompositeTypeSpecifier) parent).getName().getLastName().getLookupKey(); final char[] dtorName = name.getLookupKey(); return CharArrayUtils.equals(dtorName, className); } parent= parent.getParent(); } } } return false; } private static boolean isConstructorDtor(IASTDeclarator declarator) { if (declarator == null || !(declarator instanceof IASTFunctionDeclarator)) return false; IASTDeclSpecifier declSpec = null; IASTNode parent = findOutermostDeclarator(declarator).getParent(); if (parent instanceof IASTSimpleDeclaration) { declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); } else if (parent instanceof IASTFunctionDefinition) { declSpec = ((IASTFunctionDefinition) parent).getDeclSpecifier(); } if (declSpec != null && declSpec instanceof IASTSimpleDeclSpecifier) { return (((IASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_unspecified); } return false; } public static boolean isLastNameInUsingDeclaration(IASTName name) { IASTNode parent = name.getParent(); return parent instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName) parent).getLastName() == name && parent.getParent() instanceof ICPPASTUsingDeclaration; } public static IScope getContainingNonTemplateScope(final IASTNode inputNode) { IScope scope= getContainingScope(inputNode); while (scope instanceof ICPPTemplateScope) { scope= getContainingScope(((ICPPTemplateScope) scope).getTemplateDeclaration()); } return scope; } public static IScope getContainingScope(final IASTNode inputNode) { if (inputNode == null || inputNode instanceof IASTTranslationUnit) return null; IASTNode node= inputNode; while (node != null) { if (node instanceof IASTName && !(node instanceof ICPPASTQualifiedName)) { return getContainingScope((IASTName) node); } 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 ICPPASTRangeBasedForStatement) { return ((ICPPASTRangeBasedForStatement) parent).getScope(); } else if (parent instanceof IASTCompositeTypeSpecifier) { return ((IASTCompositeTypeSpecifier) parent).getScope(); } else if (parent instanceof ICPPASTNamespaceDefinition) { return ((ICPPASTNamespaceDefinition) parent).getScope(); } else if (parent instanceof ICPPASTSwitchStatement) { return ((ICPPASTSwitchStatement) parent).getScope(); } else if (parent instanceof ICPPASTIfStatement) { return ((ICPPASTIfStatement) parent).getScope(); } else if (parent instanceof ICPPASTWhileStatement) { return ((ICPPASTWhileStatement) parent).getScope(); } else if (parent instanceof ICPPASTTemplateDeclaration) { return ((ICPPASTTemplateDeclaration) parent).getScope(); } else if (parent instanceof ICPPASTCatchHandler) { return ((ICPPASTCatchHandler) parent).getScope(); } } else if (node instanceof IASTStatement) { return getContainingScope((IASTStatement) node); } else if (node instanceof IASTTypeId) { ASTNodeProperty prop = node.getPropertyInParent(); if (prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == ICPPASTConversionName.TYPE_ID) { node= node.getParent(); // template-id or conversion name while (node instanceof IASTName) { node= node.getParent(); } continue; } else if (prop == ICPPASTFunctionDeclarator.TRAILING_RETURN_TYPE || prop == ICPPASTFunctionDeclarator.EXCEPTION_TYPEID) { IScope result = scopeViaFunctionDtor((ICPPASTFunctionDeclarator) node.getParent()); if (result != null) return result; } } else if (node instanceof IASTParameterDeclaration || node.getPropertyInParent() == ICPPASTFunctionDeclarator.NOEXCEPT_EXPRESSION) { IASTNode parent = node.getParent(); if (parent instanceof ICPPASTFunctionDeclarator) { IScope result = scopeViaFunctionDtor((ICPPASTFunctionDeclarator) parent); if (result != null) return result; } else if (parent instanceof ICPPASTTemplateDeclaration) { return ((ICPPASTTemplateDeclaration) parent).getScope(); } } else if (node instanceof IASTInitializer) { if (node instanceof ICPPASTConstructorChainInitializer) { // The name of the member initializer is resolved in the scope of // the owner of the ctor. ICPPASTConstructorChainInitializer initializer = (ICPPASTConstructorChainInitializer) node; IASTFunctionDefinition fdef= (IASTFunctionDefinition) initializer.getParent(); IBinding binding = fdef.getDeclarator().getName().resolveBinding(); try { return binding.getScope(); } catch (DOMException e) { } } else { IASTNode parent = node.getParent(); if (parent instanceof IASTDeclarator) { IASTDeclarator dtor = (IASTDeclarator) parent; IASTName name = dtor.getName(); if (name instanceof ICPPASTQualifiedName) { return getContainingScope(name.getLastName()); } } else if (parent instanceof ICPPASTConstructorChainInitializer) { // The initializer for the member initializer is resolved in // the body of the ctor. IASTNode temp = getContainingBlockItem(node); if (temp instanceof IASTFunctionDefinition) { IASTCompoundStatement body = (IASTCompoundStatement) ((IASTFunctionDefinition) temp).getBody(); return body.getScope(); } node= parent; } } } else if (node instanceof IASTExpression) { IASTNode parent = node.getParent(); if (parent instanceof IASTForStatement) { return ((IASTForStatement) parent).getScope(); } else if (parent instanceof ICPPASTRangeBasedForStatement) { return ((ICPPASTRangeBasedForStatement) parent).getScope(); } else if (parent instanceof ICPPASTIfStatement) { return ((ICPPASTIfStatement) parent).getScope(); } else if (parent instanceof ICPPASTSwitchStatement) { return ((ICPPASTSwitchStatement) parent).getScope(); } else if (parent instanceof ICPPASTWhileStatement) { return ((ICPPASTWhileStatement) parent).getScope(); } else if (parent instanceof IASTCompoundStatement) { return ((IASTCompoundStatement) parent).getScope(); } else if (parent instanceof IASTArrayModifier) { IASTNode d = parent.getParent(); while (!(d instanceof IASTDeclarator || d instanceof IASTExpression)) { d = d.getParent(); } if (d instanceof IASTDeclarator) { IASTDeclarator dtor = (IASTDeclarator) d; while (dtor.getNestedDeclarator() != null) dtor = dtor.getNestedDeclarator(); IASTName name = dtor.getName(); if (name instanceof ICPPASTQualifiedName) { return getContainingScope(name.getLastName()); } } } else if (parent instanceof ICPPASTTemplateId && node.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) { node= parent; // template-id while (node instanceof IASTName) { node= node.getParent(); } continue; } } else if (node instanceof ICPPASTTemplateParameter) { if (node instanceof ICPPASTTemplatedTypeTemplateParameter && node != inputNode) { return ((ICPPASTTemplatedTypeTemplateParameter) node).asScope(); } IASTNode parent = node.getParent(); if (parent instanceof ICPPASTTemplateDeclaration) { return ((ICPPASTTemplateDeclaration) parent).getScope(); } } else if (node instanceof ICPPASTBaseSpecifier) { ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) node.getParent(); IASTName n = compSpec.getName().getLastName(); return getContainingScope(n); } else if (node instanceof IASTEnumerator) { node= node.getParent(); if (node instanceof ICPPASTEnumerationSpecifier) { ICPPASTEnumerationSpecifier enumSpec= (ICPPASTEnumerationSpecifier) node; IBinding binding = enumSpec.getName().resolveBinding(); if (binding instanceof ICPPEnumeration) { ICPPEnumeration enumType = (ICPPEnumeration) binding; if (enumType.isScoped()) { return enumType.asScope(); } } } } node = node.getParent(); } return new CPPScope.CPPScopeProblem(inputNode, IProblemBinding.SEMANTIC_BAD_SCOPE, inputNode.getRawSignature().toCharArray()); } private static IScope scopeViaFunctionDtor(ICPPASTFunctionDeclarator dtor) { if (ASTQueries.findTypeRelevantDeclarator(dtor) == dtor) { IASTDeclarator outerDtor = ASTQueries.findOutermostDeclarator(dtor); ASTNodeProperty prop = outerDtor.getPropertyInParent(); if (prop == IASTSimpleDeclaration.DECLARATOR) { return dtor.getFunctionScope(); } if (prop == IASTFunctionDefinition.DECLARATOR) { final IASTCompoundStatement body = (IASTCompoundStatement) ((IASTFunctionDefinition) outerDtor.getParent()).getBody(); if (body != null) return body.getScope(); return dtor.getFunctionScope(); } if (prop == ICPPASTLambdaExpression.DECLARATOR) { final IASTCompoundStatement body = ((ICPPASTLambdaExpression) outerDtor.getParent()).getBody(); if (body != null) return body.getScope(); return dtor.getFunctionScope(); } } return null; } public static IScope getContainingScope(IASTName name) { IScope scope= getContainingScopeOrNull(name); if (scope == null) { return new CPPScope.CPPScopeProblem(name, IProblemBinding.SEMANTIC_BAD_SCOPE); } return scope; } private static IScope getContainingScopeOrNull(IASTName name) { if (name == null) { return null; } IASTNode parent = name.getParent(); try { if (parent instanceof ICPPASTTemplateId) { name = (IASTName) parent; parent = name.getParent(); } if (parent instanceof ICPPASTQualifiedName) { final ICPPASTQualifiedName qname= (ICPPASTQualifiedName) parent; final ICPPASTNameSpecifier[] qualifiers= qname.getQualifier(); int i = 0; for (; i < qualifiers.length; i++) { if (qualifiers[i] == name) break; } final IASTTranslationUnit tu = parent.getTranslationUnit(); if (i == 0) { if (qname.isFullyQualified()) { if (tu == null) return null; return tu.getScope(); } if (qname.getParent() instanceof ICPPASTFieldReference) { name= qname; parent= name.getParent(); } } else { // i > 0 // For template functions we may need to resolve a template parameter // as a parent of an unknown type used as parameter type. IBinding binding = qualifiers[i - 1].resolvePreBinding(); // 7.1.3-7 Unwrap typedefs, delete cv-qualifiers. if (binding instanceof ITypedef) { IType type= getNestedType((ITypedef) binding, TDEF | CVTYPE); if (type instanceof IBinding) { binding= (IBinding) type; } } boolean done= true; IScope scope= null; if (binding instanceof ICPPClassType) { binding= (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding, name); scope= ((ICPPClassType) binding).getCompositeScope(); } else if (binding instanceof ICPPNamespace) { scope= ((ICPPNamespace) binding).getNamespaceScope(); } else if (binding instanceof ICPPEnumeration) { scope= ((ICPPEnumeration) binding).asScope(); } else if (binding instanceof ICPPUnknownBinding) { scope= ((ICPPUnknownBinding) binding).asScope(); } else if (binding instanceof IProblemBinding) { if (binding instanceof ICPPScope) scope= (IScope) binding; } else { done= false; } if (done) { if (scope == null) { return new CPPScope.CPPScopeProblem(qualifiers[i - 1], IProblemBinding.SEMANTIC_BAD_SCOPE, null); } return scope; } } } if (parent instanceof ICPPASTFieldReference) { final ICPPASTFieldReference fieldReference = (ICPPASTFieldReference) parent; IType type = fieldReference.getFieldOwnerType(); if (type instanceof ICPPParameterPackType) { type = ((ICPPParameterPackType) type).getType(); } type= getUltimateTypeUptoPointers(type); if (type instanceof ICPPClassType) { type= SemanticUtil.mapToAST(type, fieldReference); return ((ICPPClassType) type).getCompositeScope(); } else if (type instanceof ICPPUnknownBinding) { return ((ICPPUnknownBinding) type).asScope(); } else if (type instanceof ICPPUnknownType) { return new CPPUnknownTypeScope(type, null); } else { return new CPPScope.CPPScopeProblem(name, ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); } } else if (parent instanceof ICPPASTFieldDesignator) { IType type = null; IASTNode node = parent; do { if (node instanceof ICPPASTDeclarator) { type = createType((ICPPASTDeclarator) node); break; } if (node instanceof ICPPASTSimpleTypeConstructorExpression) { type = ((ICPPASTSimpleTypeConstructorExpression) node).getExpressionType(); break; } } while ((node = node.getParent()) != null); if (type != null) { type= getNestedType(type, TDEF | CVTYPE); if (type instanceof ICPPClassType) { type= SemanticUtil.mapToAST(type, name); return ((ICPPClassType) type).getCompositeScope(); } } return new CPPScope.CPPScopeProblem(name, ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); } else if (parent instanceof IASTGotoStatement || parent instanceof IASTLabelStatement) { while (!(parent instanceof IASTFunctionDefinition)) { parent = parent.getParent(); } IASTFunctionDefinition fdef = (IASTFunctionDefinition) parent; return ((ICPPASTFunctionDeclarator) fdef.getDeclarator()).getFunctionScope(); } } catch (DOMException e) { IProblemBinding problem = e.getProblem(); if (problem instanceof ICPPScope) return problem; return new CPPScope.CPPScopeProblem(problem.getASTNode(), problem.getID(), problem.getNameCharArray()); } return getContainingScope(parent); } 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 IASTForStatement) { scope = ((IASTForStatement) parent).getScope(); } else if (parent instanceof ICPPASTRangeBasedForStatement) { scope= ((ICPPASTRangeBasedForStatement) parent).getScope(); } else if (parent instanceof ICPPASTSwitchStatement) { scope = ((ICPPASTSwitchStatement) parent).getScope(); } else if (parent instanceof ICPPASTIfStatement) { scope = ((ICPPASTIfStatement) parent).getScope(); } else if (parent instanceof ICPPASTWhileStatement) { scope = ((ICPPASTWhileStatement) parent).getScope(); } else if (parent instanceof IASTStatement) { scope = getContainingScope((IASTStatement) parent); } else if (parent instanceof IASTFunctionDefinition) { final IASTFunctionDefinition fdef = (IASTFunctionDefinition) parent; if (statement instanceof ICPPASTCatchHandler) return fdef.getScope(); IASTFunctionDeclarator fnDeclarator = fdef.getDeclarator(); IASTName name = findInnermostDeclarator(fnDeclarator).getName().getLastName(); return getContainingScope(name); } if (scope == null) return getContainingScope(parent); return scope; } public static IASTNode getContainingBlockItem(IASTNode node) { if (node == null) return null; if (node.getPropertyInParent() == null) return null; 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; } else if (parent instanceof IASTExpression) { IASTNode p = parent.getParent(); if (p instanceof IASTForStatement) return parent; if (p instanceof ICPPASTRangeBasedForStatement) return parent; if (p instanceof IASTStatement) return p; } else if (parent instanceof IASTStatement || parent instanceof IASTTranslationUnit) { return parent; } else if (parent instanceof IASTFunctionDeclarator && node.getPropertyInParent() == IASTStandardFunctionDeclarator.FUNCTION_PARAMETER) { return node; } else if (parent instanceof IASTEnumerationSpecifier.IASTEnumerator) { return parent; } node = parent; } return null; } static private IBinding resolveBinding(IASTNode node) { IASTName name = null; while (node != null) { if (node instanceof IASTIdExpression) { name = ((IASTIdExpression) node).getName(); if (isLabelReference(node)) { return resolveLabel(name); } break; } else if (node instanceof ICPPASTFieldReference) { name = ((ICPPASTFieldReference) node).getFieldName(); break; } else if (node instanceof ICPPASTFieldDesignator) { name = ((ICPPASTFieldDesignator) node).getName(); break; } else if (node instanceof IASTFunctionCallExpression) { node = ((IASTFunctionCallExpression) node).getFunctionNameExpression(); } else if (node instanceof IASTUnaryExpression) { node = ((IASTUnaryExpression) node).getOperand(); } else if (node instanceof IASTBinaryExpression) { node = ((IASTBinaryExpression) node).getOperand2(); } else { node = null; } } if (name != null) { name= name.getLastName(); IBinding binding = name.getPreBinding(); if (binding == null) { binding = CPPSemantics.resolveBinding(name); name.setBinding(binding); if (name instanceof ICPPASTTemplateId && binding instanceof ICPPSpecialization) { ((ICPPASTTemplateId) name).getTemplateName().setBinding(((ICPPSpecialization) binding).getSpecializedBinding()); } } return binding; } return null; } private static class CollectProblemsAction extends ASTGenericVisitor { private List<IASTProblem> fProblems = null; CollectProblemsAction() { super(true); } private void addProblem(IASTProblem problem) { if (fProblems == null) { fProblems= new ArrayList<>(); } fProblems.add(problem); } public IASTProblem[] getProblems() { if (fProblems == null) return new IASTProblem[0]; return fProblems.toArray(new IASTProblem[fProblems.size()]); } @Override public int genericVisit(IASTNode node) { if (node instanceof IASTProblemHolder) addProblem(((IASTProblemHolder) node).getProblem()); return PROCESS_CONTINUE; } } public static class CollectDeclarationsAction extends ASTVisitor { private static final int DEFAULT_LIST_SIZE = 8; private IASTName[] decls; private IBinding[] bindings; private int idx = 0; private int kind; private char[] requiredName; private IIndex index; private static final int KIND_LABEL = 1; private static final int KIND_OBJ_FN = 2; private static final int KIND_TYPE = 3; private static final int KIND_NAMESPACE = 4; private static final int KIND_COMPOSITE = 5; private static final int KIND_TEMPLATE_PARAMETER = 6; public CollectDeclarationsAction(IBinding binding) { shouldVisitTranslationUnit = true; shouldVisitNames = true; this.decls = new IASTName[DEFAULT_LIST_SIZE]; final String bname = binding.getName(); if (bname.length() > 0 && !bname.startsWith("operator")) { //$NON-NLS-1$ requiredName= bname.toCharArray(); } this.bindings = new IBinding[] { binding }; if (binding instanceof ICPPUsingDeclaration) { this.bindings= ((ICPPUsingDeclaration) binding).getDelegates(); kind= KIND_COMPOSITE; } else if (binding instanceof ILabel) { kind = KIND_LABEL; } else if (binding instanceof ICPPTemplateParameter) { kind = KIND_TEMPLATE_PARAMETER; } else if (binding instanceof ICompositeType || binding instanceof ICPPAliasTemplate || binding instanceof ITypedef || binding instanceof IEnumeration) { kind = KIND_TYPE; } else if (binding instanceof ICPPNamespace) { kind = KIND_NAMESPACE; } else if (binding instanceof IParameter) { requiredName= null; kind = KIND_OBJ_FN; } else { kind = KIND_OBJ_FN; } } @Override public int visit(IASTTranslationUnit tu) { index = tu.getIndex(); return PROCESS_CONTINUE; } @Override public int visit(IASTName name) { if (name instanceof ICPPASTQualifiedName) return PROCESS_CONTINUE; if (requiredName != null && !CharArrayUtils.equals(name.getLookupKey(), requiredName)) { return PROCESS_CONTINUE; } ASTNodeProperty prop = name.getPropertyInParent(); if (prop == ICPPASTQualifiedName.SEGMENT_NAME) prop = name.getParent().getPropertyInParent(); switch (kind) { case KIND_TEMPLATE_PARAMETER: if (prop == ICPPASTSimpleTypeTemplateParameter.PARAMETER_NAME || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER_NAME) { break; } else if (prop == IASTDeclarator.DECLARATOR_NAME) { IASTNode d = name.getParent(); while (d.getParent() instanceof IASTDeclarator) d = d.getParent(); if (d.getPropertyInParent() == IASTParameterDeclaration.DECLARATOR) { break; } } return PROCESS_CONTINUE; case KIND_LABEL: if (prop == IASTLabelStatement.NAME) break; return PROCESS_CONTINUE; case KIND_TYPE: case KIND_COMPOSITE: if (prop == IASTCompositeTypeSpecifier.TYPE_NAME || prop == ICPPASTAliasDeclaration.ALIAS_NAME || prop == IASTEnumerationSpecifier.ENUMERATION_NAME || prop == ICPPASTUsingDeclaration.NAME) { break; } else if (prop == IASTElaboratedTypeSpecifier.TYPE_NAME) { IASTNode p = name.getParent().getParent(); if (p instanceof IASTParameterDeclaration || (p instanceof IASTSimpleDeclaration && ((IASTSimpleDeclaration) p).getDeclarators().length == 0)) { break; } } else if (prop == IASTDeclarator.DECLARATOR_NAME) { IASTNode p = name.getParent(); while (p instanceof IASTDeclarator) { p= p.getParent(); } if (p instanceof IASTSimpleDeclaration) { IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) p).getDeclSpecifier(); if (declSpec.getStorageClass() == IASTDeclSpecifier.sc_typedef) break; } } if (kind == KIND_TYPE) return PROCESS_CONTINUE; // $FALL-THROUGH$ case KIND_OBJ_FN: if (prop == IASTDeclarator.DECLARATOR_NAME || prop == IASTEnumerationSpecifier.IASTEnumerator.ENUMERATOR_NAME || prop == ICPPASTUsingDeclaration.NAME) { break; } return PROCESS_CONTINUE; case KIND_NAMESPACE: if (prop == ICPPASTNamespaceDefinition.NAMESPACE_NAME || prop == ICPPASTNamespaceAlias.ALIAS_NAME) { break; } return PROCESS_CONTINUE; } if (bindings != null) { if (isDeclarationBinding(name.resolveBinding())) { if (decls.length == idx) { decls = Arrays.copyOf(decls, decls.length * 2); } decls[idx++] = name; } } return PROCESS_CONTINUE; } private boolean isDeclarationBinding(IBinding nameBinding) { if (nameBinding != null) { for (IBinding binding : bindings) { if (areEquivalentBindings(nameBinding, binding, index)) { return true; } // A using declaration is a declaration for the references of its delegates. if (nameBinding instanceof ICPPUsingDeclaration) { if (ArrayUtil.contains(((ICPPUsingDeclaration) nameBinding).getDelegates(), binding)) { return true; } } } } return false; } public IASTName[] getDeclarations() { if (idx < decls.length) { decls = Arrays.copyOf(decls, idx); } return decls; } } private static boolean areEquivalentBindings(IBinding binding1, IBinding binding2, IIndex index) { if (binding1.equals(binding2)) { return true; } if ((binding1 instanceof IIndexBinding) != (binding2 instanceof IIndexBinding) && index != null) { // Even though we know one of them is an index binding, we need to adapt both because // they might not come from an index with the same number of fragments. So one of them // could be a composite binding and the other one not. binding1 = index.adaptBinding(binding1); binding2 = index.adaptBinding(binding2); if (binding1 == null || binding2 == null) { return false; } if (binding1.equals(binding2)) { return true; } } return false; } protected static IBinding unwindBinding(IBinding binding) { while (true) { if (binding instanceof ICPPSpecialization) { binding= ((ICPPSpecialization) binding).getSpecializedBinding(); } else { break; } } return binding; } public static class CollectReferencesAction extends ASTVisitor { private static final int DEFAULT_LIST_SIZE = 8; private IASTName[] refs; private IBinding[] bindings; private int idx = 0; private int kind; private IIndex index; private static final int KIND_LABEL = 1; private static final int KIND_OBJ_FN = 2; private static final int KIND_TYPE = 3; private static final int KIND_NAMESPACE = 4; private static final int KIND_COMPOSITE = 5; public CollectReferencesAction(IBinding binding) { shouldVisitTranslationUnit = true; shouldVisitNames = true; this.refs = new IASTName[DEFAULT_LIST_SIZE]; binding = unwindBinding(binding); this.bindings = new IBinding[] { binding }; if (binding instanceof ICPPUsingDeclaration) { this.bindings= ((ICPPUsingDeclaration) binding).getDelegates(); kind= KIND_COMPOSITE; } else if (binding instanceof ILabel) { kind = KIND_LABEL; } else if (binding instanceof ICompositeType || binding instanceof ITypedef || binding instanceof IEnumeration) { kind = KIND_TYPE; } else if (binding instanceof ICPPNamespace) { kind = KIND_NAMESPACE; } else if (binding instanceof ICPPTemplateParameter) { kind = KIND_COMPOSITE; } else { kind = KIND_OBJ_FN; } } @Override public int visit(IASTTranslationUnit tu) { index = tu.getIndex(); return PROCESS_CONTINUE; } @Override public int visit(IASTName name) { if (name instanceof ICPPASTQualifiedName || name instanceof ICPPASTTemplateId) return PROCESS_CONTINUE; ASTNodeProperty prop = name.getPropertyInParent(); ASTNodeProperty p2 = null; if (prop == ICPPASTQualifiedName.SEGMENT_NAME) { p2 = prop; prop = name.getParent().getPropertyInParent(); } switch (kind) { case KIND_LABEL: if (prop == IASTGotoStatement.NAME || prop == IASTIdExpression.ID_NAME) break; return PROCESS_CONTINUE; case KIND_TYPE: case KIND_COMPOSITE: if (prop == IASTNamedTypeSpecifier.NAME || prop == ICPPASTPointerToMember.NAME || prop == ICPPASTUsingDeclaration.NAME || prop == ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.NAME_SPECIFIER || prop == ICPPASTTemplateId.TEMPLATE_NAME || p2 == ICPPASTQualifiedName.SEGMENT_NAME) { break; } else if (prop == IASTElaboratedTypeSpecifier.TYPE_NAME) { IASTNode p = name.getParent().getParent(); if (!(p instanceof IASTSimpleDeclaration) || ((IASTSimpleDeclaration) p).getDeclarators().length > 0) { break; } } if (kind == KIND_TYPE) return PROCESS_CONTINUE; //$FALL-THROUGH$ case KIND_OBJ_FN: if (prop == IASTIdExpression.ID_NAME || prop == IASTFieldReference.FIELD_NAME || prop == ICPPASTUsingDirective.QUALIFIED_NAME || prop == ICPPASTUsingDeclaration.NAME || prop == IASTFunctionCallExpression.FUNCTION_NAME || prop == ICPPASTUsingDeclaration.NAME || prop == IASTNamedTypeSpecifier.NAME || prop == ICPPASTConstructorChainInitializer.MEMBER_ID || prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == ICPPASTCapture.IDENTIFIER || prop == IASTImplicitNameOwner.IMPLICIT_NAME) { break; } return PROCESS_CONTINUE; case KIND_NAMESPACE: if (prop == ICPPASTUsingDirective.QUALIFIED_NAME || prop == ICPPASTNamespaceAlias.MAPPING_NAME || prop == ICPPASTUsingDeclaration.NAME || p2 == ICPPASTQualifiedName.SEGMENT_NAME) { break; } return PROCESS_CONTINUE; } if (bindings != null) { if (isReferenceBinding(name.resolveBinding())) { if (refs.length == idx) { refs = Arrays.copyOf(refs, refs.length * 2); } refs[idx++] = name; } } return PROCESS_CONTINUE; } private boolean isReferenceBinding(IBinding nameBinding) { nameBinding= unwindBinding(nameBinding); if (nameBinding != null) { for (IBinding binding : bindings) { if (areEquivalentBindings(nameBinding, binding, index)) { return true; } } if (nameBinding instanceof ICPPUsingDeclaration) { IBinding[] delegates= ((ICPPUsingDeclaration) nameBinding).getDelegates(); for (IBinding delegate : delegates) { if (isReferenceBinding(delegate)) { return true; } } } } return false; } public IASTName[] getReferences() { if (idx < refs.length) { refs = Arrays.copyOf(refs, idx); } return refs; } } /** * Generate a function type for an implicit function. * NOTE: This does not correctly handle parameters with typedef types. */ public static ICPPFunctionType createImplicitFunctionType(IType returnType, IParameter[] parameters, boolean isConst, boolean isVolatile) { IType[] pTypes = new IType[parameters.length]; IType pt = null; for (int i = 0; i < parameters.length; i++) { pt = parameters[i].getType(); // remove qualifiers if (pt instanceof IQualifierType) { pt= ((IQualifierType) pt).getType(); } if (pt instanceof IArrayType) { pt = new CPPPointerType(((IArrayType) pt).getType()); } else if (pt instanceof IFunctionType) { pt = new CPPPointerType(pt); } pTypes[i] = pt; } return new CPPFunctionType(returnType, pTypes, isConst, isVolatile, false, false, false); } /** * Creates the type for the given type id. */ public static IType createType(IASTTypeId typeid) { return createType(typeid.getAbstractDeclarator()); } /** * Creates the type for a parameter declaration. */ public static IType createType(final ICPPASTParameterDeclaration pdecl, boolean forFuncType) { IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier(); ICPPASTDeclarator pDtor = pdecl.getDeclarator(); IType pt = createType(pDeclSpec); if (pDtor != null) { pt = createType(pt, pDtor); } pt= adjustParameterType(pt, forFuncType); if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) { pt= new CPPParameterPackType(pt); } return pt; } private static IType createType(IType returnType, ICPPASTFunctionDeclarator fnDtor) { IType[] pTypes = createParameterTypes(fnDtor); IASTName name = fnDtor.getName().getLastName(); if (name instanceof ICPPASTConversionName) { returnType = createType(((ICPPASTConversionName) name).getTypeId()); } else { returnType = applyAttributes(returnType, fnDtor); returnType = getPointerTypes(returnType, fnDtor); } RefQualifier refQualifier = fnDtor.getRefQualifier(); CPPFunctionType type = new CPPFunctionType(returnType, pTypes, fnDtor.isConst(), fnDtor.isVolatile(), refQualifier != null, refQualifier == RefQualifier.RVALUE, fnDtor.takesVarArgs()); final IASTDeclarator nested = fnDtor.getNestedDeclarator(); if (nested != null) { return createType(type, nested); } return type; } /** * Creates an array of types for the parameters of the given function declarator. */ public static IType[] createParameterTypes(ICPPASTFunctionDeclarator fnDtor) { ICPPASTParameterDeclaration[] params = fnDtor.getParameters(); IType[] pTypes = new IType[params.length]; for (int i = 0; i < params.length; i++) { pTypes[i]= createType(params[i], true); } if (pTypes.length == 1 && SemanticUtil.isVoidType(pTypes[0])) { return IType.EMPTY_TYPE_ARRAY; // f(void) is the same as f(). } return pTypes; } /** * Adjusts the parameter type according to 8.3.5-3: * cv-qualifiers are deleted, arrays and function types are converted to pointers. */ static IType adjustParameterType(final IType pt, boolean forFunctionType) { // Bug 239975 IType t= SemanticUtil.getNestedType(pt, TDEF); if (t instanceof IArrayType) { IArrayType at = (IArrayType) t; return new CPPPointerType(at.getType()); } if (t instanceof IFunctionType) { return new CPPPointerType(pt); } // 8.3.5-3 // Any cv-qualifier modifying a parameter type is deleted. The parameter type remains // to be qualified. if (forFunctionType && SemanticUtil.getCVQualifier(t) != CVQualifier.NONE) { return SemanticUtil.getNestedType(t, TDEF | ALLCVQ); } return pt; } private static IType getPointerTypes(IType type, IASTDeclarator declarator) { IASTPointerOperator[] ptrOps = declarator.getPointerOperators(); for (IASTPointerOperator ptrOp : ptrOps) { if (ptrOp instanceof ICPPASTPointerToMember) { type = new CPPPointerToMemberType(type, (ICPPASTPointerToMember) ptrOp); } else if (ptrOp instanceof IASTPointer) { type = new CPPPointerType(type, (IASTPointer) ptrOp); } else if (ptrOp instanceof ICPPASTReferenceOperator) { final ICPPASTReferenceOperator refOp = (ICPPASTReferenceOperator) ptrOp; type = new CPPReferenceType(type, refOp.isRValueReference()); } } 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 CPPBasicType(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 CPPBasicType(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 CPPBasicType(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 CPPBasicType(IBasicType.Kind.eInt, modifier | getSignModifiers(basicType)); } else if (CharArrayUtils.equals(mode, "__word__") || CharArrayUtils.equals(mode, "word")) { //$NON-NLS-1$ //$NON-NLS-2$ type = new CPPBasicType(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); } private static IType getArrayType(IType type, IASTArrayDeclarator declarator) { IASTArrayModifier[] mods = declarator.getArrayModifiers(); for (int i = mods.length; --i >= 0;) { IASTArrayModifier mod = mods[i]; IASTExpression sizeExpression = mod.getConstantExpression(); if (sizeExpression != null) { type = new CPPArrayType(type, sizeExpression); } else { IValue sizeValue = null; IASTInitializer initializer = declarator.getInitializer(); if (initializer instanceof IASTEqualsInitializer) { IASTInitializerClause clause = ((IASTEqualsInitializer) initializer).getInitializerClause(); if (clause instanceof IASTInitializerList) { IASTInitializerClause[] clauses = ((IASTInitializerList) clause).getClauses(); sizeValue = IntegralValue.create(clauses.length); } else if (clause instanceof ICPPASTLiteralExpression) { ICPPEvaluation value = ((ICPPEvaluationOwner) clause).getEvaluation(); IType valueType = value.getType(clause); if (valueType instanceof IArrayType) { sizeValue = ((IArrayType) valueType).getSize(); } } } type = new CPPArrayType(type, sizeValue); } } return type; } public static IType createType(IASTDeclarator declarator) { if (declarator == null) return new ProblemType(ISemanticProblem.TYPE_NO_NAME); declarator= findOutermostDeclarator(declarator); IASTNode parent = declarator.getParent(); IASTDeclSpecifier declSpec = null; boolean isPackExpansion= false; if (parent instanceof IASTSimpleDeclaration) { declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); } else if (parent instanceof IASTParameterDeclaration) { declSpec = ((IASTParameterDeclaration) parent).getDeclSpecifier(); } else if (parent instanceof IASTFunctionDefinition) { declSpec = ((IASTFunctionDefinition) parent).getDeclSpecifier(); } else if (parent instanceof ICPPASTTypeId) { final ICPPASTTypeId typeId = (ICPPASTTypeId) parent; declSpec = typeId.getDeclSpecifier(); isPackExpansion= typeId.isPackExpansion(); } else { throw new IllegalArgumentException(); } if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec; int declSpecifierType = simpleDeclSpecifier.getType(); if (declSpecifierType == IASTSimpleDeclSpecifier.t_auto) { return createAutoType(declSpec, declarator); } else if (declSpecifierType == IASTSimpleDeclSpecifier.t_decltype_auto) { return createDecltypeAutoType(declarator, simpleDeclSpecifier); } } IType type = createType(declSpec); type = makeConstIfConstexpr(type, declSpec, declarator); type = createType(type, declarator); // C++ specification 8.3.4.3 and 8.5.1.4 IASTNode initClause= declarator.getInitializer(); if (initClause instanceof IASTEqualsInitializer) { initClause= ((IASTEqualsInitializer) initClause).getInitializerClause(); } if (initClause instanceof IASTInitializerList) { IType t= SemanticUtil.getNestedType(type, TDEF); if (t instanceof IArrayType) { IArrayType at= (IArrayType) t; if (at.getSize() == null) { type= new CPPArrayType(at.getType(), IntegralValue.create(((IASTInitializerList) initClause).getSize())); } } } if (isPackExpansion) { type= new CPPParameterPackType(type); } return type; } private static IType createDecltypeAutoType(IASTDeclarator declarator, ICPPASTSimpleDeclSpecifier simpleDeclSpecifier) { IASTInitializerClause initializerClause = getInitializerClauseForDecltypeAuto(declarator); if (initializerClause instanceof IASTExpression) { return getDeclType((IASTExpression) initializerClause); } return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE); } private static IASTInitializerClause getInitializerClauseForDecltypeAuto(IASTDeclarator declarator) { IASTInitializer initializer = declarator.getInitializer(); if (initializer == null) { ICPPASTNewExpression newExpression = findAncestorWithType(declarator, ICPPASTNewExpression.class); if (newExpression != null) { initializer = newExpression.getInitializer(); } } if (initializer instanceof IASTEqualsInitializer) { return ((IASTEqualsInitializer) initializer).getInitializerClause(); } else if (initializer instanceof ICPPASTConstructorInitializer) { ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer; IASTInitializerClause[] arguments = constructorInitializer.getArguments(); if (arguments.length == 1) { return arguments[0]; } } else if (initializer instanceof IASTInitializerList) { IASTInitializerList initializerList = (IASTInitializerList) initializer; IASTInitializerClause[] clauses = initializerList.getClauses(); if (clauses.length == 1) { return clauses[0]; } } return null; } private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator) { Set<IASTDeclSpecifier> recursionProtectionSet = autoTypeDeclSpecs.get(); if (!recursionProtectionSet.add(declSpec)) { // Detected a self referring auto type, e.g.: auto x = x; return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } try { if (declarator instanceof ICPPASTFunctionDeclarator) { return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator); } ICPPASTInitializerClause autoInitClause= null; IASTNode parent = declarator.getParent().getParent(); if (parent instanceof ICPPASTNewExpression) { IASTInitializer initializer = ((ICPPASTNewExpression) parent).getInitializer(); if (initializer != null) { IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initializer).getArguments(); if (arguments.length == 1) { autoInitClause = (ICPPASTInitializerClause) arguments[0]; } } } else if (parent instanceof ICPPASTRangeBasedForStatement) { // See 6.5.4 The range-based for statement [stmt.ranged] ICPPASTRangeBasedForStatement forStmt= (ICPPASTRangeBasedForStatement) parent; IASTInitializerClause forInit = forStmt.getInitializerClause(); IASTExpression beginExpr= null; if (forInit instanceof IASTExpression) { final IASTExpression expr = (IASTExpression) forInit; IType type= SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE); if (type instanceof IArrayType) { beginExpr= expr.copy(); } } if (beginExpr == null) { IASTImplicitName[] implicits= forStmt.getImplicitNames(); if (implicits.length > 0) { IBinding b= implicits[0].getBinding(); CPPASTName name= new CPPASTName(); name.setBinding(b); IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() }; if (b instanceof ICPPMethod && forInit instanceof IASTExpression) { beginExpr= new CPPASTFunctionCallExpression( new CPPASTFieldReference(name, (IASTExpression) forInit.copy()), beginCallArguments); } else { beginExpr= new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments); } } else { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } } autoInitClause= new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr); autoInitClause.setParent(forStmt); autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER); } else if (parent instanceof IASTCompositeTypeSpecifier && declSpec.getStorageClass() != IASTDeclSpecifier.sc_static) { // Non-static auto-typed class members are not allowed. return new ProblemType(ISemanticProblem.TYPE_AUTO_FOR_NON_STATIC_FIELD); } else { IASTInitializer initClause= declarator.getInitializer(); if (initClause instanceof IASTEqualsInitializer) { autoInitClause= (ICPPASTInitializerClause) ((IASTEqualsInitializer) initClause).getInitializerClause(); } else if (initClause instanceof ICPPASTConstructorInitializer) { IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initClause).getArguments(); if (arguments.length == 1) autoInitClause = (ICPPASTInitializerClause) arguments[0]; } else if (initClause instanceof ICPPASTInitializerClause) { autoInitClause= (ICPPASTInitializerClause) initClause; } } return createAutoType(autoInitClause, declSpec, declarator); } finally { recursionProtectionSet.remove(declSpec); } } private static IType createAutoType(ICPPASTInitializerClause initClause, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { // C++0x: 7.1.6.4 if (initClause == null) { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } IType type = AutoTypeResolver.AUTO_TYPE; IType initType = null; ValueCategory valueCat= null; ICPPClassTemplate initializer_list_template = null; if (initClause instanceof ICPPASTInitializerList) { initializer_list_template = get_initializer_list(declSpec); if (initializer_list_template == null) { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } type = (IType) CPPTemplates.instantiate(initializer_list_template, new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause); if (type instanceof IProblemBinding) { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } } type = decorateType(type, declSpec, declarator); final ICPPEvaluation evaluation = ((ICPPEvaluationOwner) initClause).getEvaluation(); initType= evaluation.getType(declarator); valueCat= evaluation.getValueCategory(declarator); if (initType == null || initType instanceof ISemanticProblem) { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } ICPPFunctionTemplate template = new AutoTypeResolver(type); CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1); TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType), Collections.singletonList(valueCat), paramMap, initClause); ICPPTemplateArgument argument = paramMap.getArgument(0, 0); if (argument == null) { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } type = argument.getTypeValue(); IType t = SemanticUtil.substituteTypedef(type, initType); if (t != null) type = t; if (initClause instanceof ICPPASTInitializerList) { type = (IType) CPPTemplates.instantiate(initializer_list_template, new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause); } return decorateType(type, declSpec, declarator); } /** * C++0x: [8.3.5-2] */ private static IType createAutoFunctionType(IASTDeclSpecifier declSpec, ICPPASTFunctionDeclarator declarator) { IASTTypeId id= declarator.getTrailingReturnType(); if (id == null) return new ProblemType(ISemanticProblem.TYPE_NO_NAME); IType t= createType(id.getAbstractDeclarator()); t= qualifyType(t, declSpec); return createType(t, declarator); } public static IType createType(IASTDeclSpecifier declSpec) { IType type = getBaseType(declSpec); return qualifyType(type, declSpec); } private static IType getBaseType(IASTDeclSpecifier declSpec) { IASTName name; if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { name = ((ICPPASTCompositeTypeSpecifier) declSpec).getName(); } else if (declSpec instanceof ICPPASTNamedTypeSpecifier) { name = ((ICPPASTNamedTypeSpecifier) declSpec).getName(); } else if (declSpec instanceof ICPPASTElaboratedTypeSpecifier) { name = ((ICPPASTElaboratedTypeSpecifier) declSpec).getName(); } else if (declSpec instanceof IASTEnumerationSpecifier) { name = ((IASTEnumerationSpecifier) declSpec).getName(); } else if (declSpec instanceof ICPPASTTypeTransformationSpecifier) { ICPPASTTypeTransformationSpecifier spec = (ICPPASTTypeTransformationSpecifier) declSpec; return new CPPUnaryTypeTransformation(spec.getOperator(), createType(spec.getOperand())); } else if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { ICPPASTSimpleDeclSpecifier spec = (ICPPASTSimpleDeclSpecifier) declSpec; // Check for decltype(expr) IType type = getDeclType(spec); if (type != null) return type; return new CPPBasicType(spec); } else { throw new IllegalArgumentException(); } if (name == null) return new ProblemType(ISemanticProblem.TYPE_NO_NAME); IBinding binding = name.resolvePreBinding(); if (!(binding instanceof IProblemBinding)) { if (binding instanceof ICPPConstructor) return ((ICPPConstructor) binding).getClassOwner(); if (binding instanceof IType) return (IType) binding; } return new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME); } private static IType decorateType(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { type = qualifyType(type, declSpec); type = makeConstIfConstexpr(type, declSpec, declarator); return createType(type, declarator); } private static IType makeConstIfConstexpr(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { // [dcl.constexpr] p9: constexpr on a variable makes it const if (!(declarator instanceof IASTFunctionDeclarator)) { if (declSpec instanceof ICPPASTDeclSpecifier) { if (((ICPPASTDeclSpecifier) declSpec).isConstexpr()) { return SemanticUtil.constQualify(type); } } } return type; } private static IType qualifyType(IType type, IASTDeclSpecifier declSpec) { return SemanticUtil.addQualifiers(type, declSpec.isConst(), declSpec.isVolatile(), declSpec.isRestrict()); } private static IType createType(IType baseType, IASTDeclarator declarator) { if (declarator instanceof ICPPASTFunctionDeclarator) return createType(baseType, (ICPPASTFunctionDeclarator) declarator); IType type = baseType; type = applyAttributes(type, declarator); type = getPointerTypes(type, declarator); if (declarator instanceof IASTArrayDeclarator) type = getArrayType(type, (IASTArrayDeclarator) declarator); IASTDeclarator nested = declarator.getNestedDeclarator(); if (nested != null) { return createType(type, nested); } return type; } /** * Computes the type for decltype(expr) or typeof(expr). */ private static IType getDeclType(ICPPASTSimpleDeclSpecifier spec) { IASTExpression expr = spec.getDeclTypeExpression(); if (expr == null) { return null; } int specifierType = spec.getType(); if (specifierType == IASTSimpleDeclSpecifier.t_decltype) { return getDeclType(expr); } return expr.getExpressionType(); } /** * Computes the type for an expression in decltype(expr) context. */ private static IType getDeclType(IASTExpression expr) { IASTName namedEntity= null; if (expr instanceof IASTIdExpression) { namedEntity= ((IASTIdExpression) expr).getName(); } else if (expr instanceof IASTFieldReference) { namedEntity= ((IASTFieldReference) expr).getFieldName(); } if (namedEntity != null) { IBinding b= namedEntity.resolvePreBinding(); if (b instanceof IType) { return (IType) b; } if (b instanceof IVariable) { return ((IVariable) b).getType(); } if (b instanceof IFunction) { return ((IFunction) b).getType(); } } IType type = expr.getExpressionType(); switch (expr.getValueCategory()) { case XVALUE: type= new CPPReferenceType(type, true); break; case LVALUE: type= new CPPReferenceType(type, false); break; case PRVALUE: break; } return type; } public static IType getImpliedObjectType(IScope scope) { try { IASTNode node = null; while (scope != null) { if (scope instanceof ICPPBlockScope || scope instanceof ICPPFunctionScope) { node = ASTInternal.getPhysicalNodeOfScope(scope); if (node instanceof IASTFunctionDeclarator) break; if (node.getParent() instanceof IASTFunctionDefinition) break; } else if (scope instanceof ICPPClassScope) { // Reached a class scope without a function scope in between. // Might be in the default member initializer on a field. IType type = ((ICPPClassScope) scope).getClassType(); if (type instanceof ICPPClassTemplate) { type= (ICPPClassType) ((ICPPClassTemplate) type).asDeferredInstance(); } return type; } scope = scope.getParent(); } if (node != null) { if (node.getParent() instanceof IASTFunctionDefinition) { IASTFunctionDefinition def = (IASTFunctionDefinition) node.getParent(); node = def.getDeclarator(); } if (node instanceof IASTFunctionDeclarator) { ICPPASTFunctionDeclarator dtor = (ICPPASTFunctionDeclarator) node; IASTName funcName = findInnermostDeclarator(dtor).getName().getLastName(); IScope s = getContainingScope(funcName); while (s instanceof ICPPTemplateScope) { s = s.getParent(); } if (s instanceof ICPPClassScope) { ICPPClassScope cScope = (ICPPClassScope) s; IType type = cScope.getClassType(); if (type instanceof ICPPClassTemplate) { type= (ICPPClassType) ((ICPPClassTemplate) type).asDeferredInstance(); } return SemanticUtil.addQualifiers(type, dtor.isConst(), dtor.isVolatile(), false); } } } } catch (DOMException e) { return e.getProblem(); } return null; } public static IType getPointerDiffType(final IASTNode point) { IType t= getStdType(point, PTRDIFF_T); return t != null ? t : CPPBasicType.LONG; } private static IType getStdType(final IASTNode node, char[] name) { if (node == null) return null; ASTTranslationUnit ast = (ASTTranslationUnit) node.getTranslationUnit(); IBinding[] std= ast.getScope().find(STD, ast); for (IBinding binding : std) { if (binding instanceof ICPPNamespace) { final ICPPNamespaceScope scope = ((ICPPNamespace) binding).getNamespaceScope(); IBinding[] bs= CPPSemantics.findBindings(scope, name, false, node); if (bs.length > 0) { for (IBinding b : bs) { if (b instanceof IType && CPPSemantics.declaredBefore(b, node, false)) { return (IType) b; } } } } } return null; } public static IType get_type_info(IASTNode point) { IType t= getStdType(point, TYPE_INFO); return t != null ? t : CPPBasicType.INT; } public static IType get_SIZE_T(IASTNode sizeofExpr) { IType t= getStdType(sizeofExpr, SIZE_T); return t != null ? t : CPPBasicType.UNSIGNED_LONG; } public static ICPPClassTemplate get_initializer_list(IASTNode node) { IType t= getStdType(node, INITIALIZER_LIST); if (t instanceof ICPPClassTemplate) return (ICPPClassTemplate) t; return null; } public static IASTProblem[] getProblems(IASTTranslationUnit tu) { CollectProblemsAction action = new CollectProblemsAction(); tu.accept(action); return action.getProblems(); } public static IASTName[] getReferences(IASTTranslationUnit tu, IBinding binding) { CollectReferencesAction action = new CollectReferencesAction(binding); tu.accept(action); return action.getReferences(); } public static IASTName[] getImplicitReferences(IASTTranslationUnit tu, IBinding binding) { CollectReferencesAction action = new CollectReferencesAction(binding) { { shouldVisitNames = false; shouldVisitImplicitNames = true; shouldVisitImplicitNameAlternates = true; } }; tu.accept(action); return action.getReferences(); } public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding) { CollectDeclarationsAction action = new CollectDeclarationsAction(binding); tu.accept(action); IASTName[] found = action.getDeclarations(); if (found.length == 0 && binding instanceof ICPPSpecialization && binding instanceof ICPPInternalBinding) { IASTNode node = ((ICPPInternalBinding) binding).getDefinition(); if (node == null) { IASTNode[] nds = ((ICPPInternalBinding) binding).getDeclarations(); if (nds != null && nds.length > 0) node = nds[0]; } if (node != null) { IASTName name = null; if (node instanceof IASTDeclarator) { name = ((IASTDeclarator) node).getName(); } else if (node instanceof IASTName) { name = (IASTName) node; } if (name != null) found = new IASTName[] { name }; } } return found; } public static String[] getQualifiedName(IBinding binding) { String[] ns = null; for (IBinding owner= binding.getOwner(); owner != null; owner= owner.getOwner()) { if (owner instanceof ICPPEnumeration && !((ICPPEnumeration) owner).isScoped()) { continue; } String name= owner.getName(); if (name == null) break; if (owner instanceof ICPPFunction) break; if (owner instanceof ICPPNamespace && name.length() == 0) { continue; } ns = ArrayUtil.append(String.class, ns, name); } ns = ArrayUtil.trim(String.class, ns); String[] result = new String[ns.length + 1]; for (int i = ns.length; --i >= 0;) { result[ns.length - i - 1] = ns[i]; } result[ns.length]= binding.getName(); return result; } public static char[][] getQualifiedNameCharArray(IBinding binding) { char[][] ns = EMPTY_CHAR_ARRAY_ARRAY; ns = ArrayUtil.append(ns, binding.getNameCharArray()); for (IBinding owner= binding.getOwner(); owner != null; owner= owner.getOwner()) { char[] name= owner.getNameCharArray(); if (name == null) break; if (owner instanceof ICPPFunction) break; if (owner instanceof ICPPNamespace && name.length == 0) continue; ns = ArrayUtil.append(ns, name); } ns = ArrayUtil.trim(ns); ArrayUtil.reverse(ns); return ns; } public static boolean isExternC(IASTNode node) { while (node != null) { node= node.getParent(); if (node instanceof ICPPASTLinkageSpecification) { if ("\"C\"".equals(((ICPPASTLinkageSpecification) node).getLiteral())) { //$NON-NLS-1$ return true; } } } return false; } public static boolean isExternC(IASTNode definition, IASTNode[] declarations) { if (isExternC(definition)) return true; if (declarations != null) { for (IASTNode element : declarations) { if (isExternC(element)) return true; } } return false; } @Deprecated public static boolean isLValueReference(IType t) { t= SemanticUtil.getNestedType(t, TDEF); return t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference(); } /** * Searches for the function or class enclosing the given node. May return <code>null</code>. */ public static IBinding findEnclosingFunctionOrClass(IASTNode node) { IASTName name = null; for (; node != null; node= node.getParent()) { if (node instanceof IASTFunctionDefinition) { 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(); } public static IBinding findNameOwner(IASTName name, boolean allowFunction) { IASTNode node= name.getLastName(); while (node instanceof IASTName) { if (node instanceof ICPPASTQualifiedName) { ICPPASTNameSpecifier[] segments = ((ICPPASTQualifiedName) node).getAllSegments(); int i = segments.length; while (--i >= 0) { if (segments[i] == name) { break; } } if (--i < 0) break; IBinding binding = segments[i].resolveBinding(); if (binding instanceof IIndexBinding && binding instanceof ICPPClassType) { binding = (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding, name); } return bindingToOwner(binding); } name= (IASTName) node; node= node.getParent(); } return findDeclarationOwner(node, allowFunction); } private static IBinding bindingToOwner(IBinding b) { if (b instanceof ITypedef) { IType t= SemanticUtil.getNestedType((IType) b, TDEF); if (t instanceof IBinding) return (IBinding) t; return b; } while (b instanceof ICPPNamespaceAlias) { b= ((ICPPNamespaceAlias) b).getBinding(); } return b; } /** * Searches for the first class, namespace, or function, if <code>allowFunction</code> * is <code>true</code>, 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) { IASTName name = findDeclarationOwnerDefinition(node, allowFunction); if (name == null) return null; return name.resolveBinding(); } public static IASTName findDeclarationOwnerDefinition(IASTNode node, boolean allowFunction) { // Search for declaration boolean isNonSimpleElabDecl= false; while (!(node instanceof IASTDeclaration) && !(node instanceof ICPPASTLambdaExpression)) { if (node == null) return null; if (node instanceof IASTElaboratedTypeSpecifier) { isNonSimpleElabDecl= true; final IASTNode parent= node.getParent(); if (parent instanceof IASTSimpleDeclaration) { final IASTSimpleDeclaration decl = (IASTSimpleDeclaration) parent; if (decl.getDeclarators().length == 0) { isNonSimpleElabDecl= false; } } } else if (node instanceof IASTEnumerator) { break; } node= node.getParent(); } boolean isFriend= isFriendDeclaration(node); // Search for enclosing binding. for (node= node.getParent(); node != null; node= node.getParent()) { if (node instanceof IASTFunctionDefinition) { if (allowFunction) { IASTDeclarator dtor= findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator()); if (dtor != null) { return dtor.getName(); } } return null; } if (node instanceof IASTCompositeTypeSpecifier) { if (isFriend || isNonSimpleElabDecl) continue; return ((IASTCompositeTypeSpecifier) node).getName(); } if (node instanceof ICPPASTNamespaceDefinition) { return ((ICPPASTNamespaceDefinition) node).getName(); } if (node instanceof ICPPASTEnumerationSpecifier) { return ((ICPPASTEnumerationSpecifier) node).getName(); } if (node instanceof ICPPASTLambdaExpression) { return ((ICPPASTLambdaExpression) node).getClosureTypeName(); } } return null; } public static boolean doesNotSpecifyType(IASTDeclSpecifier declspec) { if (declspec instanceof ICPPASTSimpleDeclSpecifier) { ICPPASTSimpleDeclSpecifier ds= (ICPPASTSimpleDeclSpecifier) declspec; if (ds.getType() == IASTSimpleDeclSpecifier.t_unspecified) { if (ds.isShort() || ds.isLong() || ds.isLongLong() || ds.isSigned() || ds.isUnsigned()) return false; return true; } } return false; } public static ICPPASTDeclarator findInnermostDeclarator(ICPPASTDeclarator dtor) { return (ICPPASTDeclarator) ASTQueries.findInnermostDeclarator(dtor); } /** * Traverses a chain of nested homogeneous left-to-right-associative binary expressions and * returns a list of their operands in left-to-right order. For example, for the expression * a + b * c + d, it will return a list containing expressions: a, b * c, and d. * * @param binaryExpression the top-level binary expression * @return a list of expression operands from left to right */ public static IASTExpression[] getOperandsOfMultiExpression(IASTBinaryExpression binaryExpression) { int operator = binaryExpression.getOperator(); IASTExpression[] operands = new IASTExpression[2]; IASTExpression node; int len = 0; do { operands = ArrayUtil.appendAt(operands, len++, binaryExpression.getOperand2()); node = binaryExpression.getOperand1(); if (!(node instanceof IASTBinaryExpression)) { break; } binaryExpression = (IASTBinaryExpression) node; } while (binaryExpression.getOperator() == operator); operands = ArrayUtil.appendAt(operands, len++, node); operands = ArrayUtil.trim(operands, len); ArrayUtil.reverse(operands); return operands; } }