/******************************************************************************* * Copyright (c) 2004, 2011 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) - Initial API and implementation * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) * Mike Kucera (IBM) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeOrFunctionSet; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCat; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.cdt.core.dom.IName; 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.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.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.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; 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.IASTLabelStatement; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNameOwner; 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.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; 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.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; 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.IVariable; 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.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; 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.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.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.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; 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.ICPPASTUnaryExpression; 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.ICPPBase; 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.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; 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.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; 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.ICPPMember; 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.ICPPNamespaceScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; 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.ICPPTemplateDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; 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.ICPPTemplateTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.DebugUtil; import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTQualifiedName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTUnaryExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPCompositeBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceScope; 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.CPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownClass; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDeclaration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDirective; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPClassSpecializationScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.TypeSelection; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank; import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.core.runtime.CoreException; /** * Name resolution */ public class CPPSemantics { /** * The maximum depth to search ancestors before assuming infinite looping. */ public static final int MAX_INHERITANCE_DEPTH= 16; public static final ASTNodeProperty STRING_LOOKUP_PROPERTY = new ASTNodeProperty("CPPSemantics.STRING_LOOKUP_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$ public static final String EMPTY_NAME = ""; //$NON-NLS-1$ public static final char[] OPERATOR_ = new char[] {'o','p','e','r','a','t','o','r',' '}; private static final char[] CALL_FUNCTION = "call-function".toCharArray(); //$NON-NLS-1$ public static final IType VOID_TYPE = new CPPBasicType(Kind.eVoid, 0); public static final IType INT_TYPE = new CPPBasicType(Kind.eInt, 0); // Set to true for debugging. public static boolean traceBindingResolution = false; public static int traceIndent= 0; // special return value for costForFunctionCall private static final FunctionCost CONTAINS_DEPENDENT_TYPES = new FunctionCost(null, 0); static protected IBinding resolveBinding(IASTName name) { if (traceBindingResolution) { for (int i = 0; i < traceIndent; i++) System.out.print(" "); //$NON-NLS-1$ System.out.println("Resolving " + name + ':' + ((ASTNode) name).getOffset()); //$NON-NLS-1$ traceIndent++; } if (name instanceof CPPASTNameBase) { ((CPPASTNameBase) name).incResolutionDepth(); } // 1: get some context info off of the name to figure out what kind of lookup we want LookupData data = createLookupData(name); try { // 2: lookup lookup(data, null); // Perform argument dependent lookup if (data.checkAssociatedScopes() && !data.hasTypeOrMemberFunctionResult()) { doKoenigLookup(data); } } catch (DOMException e) { data.problem = (ProblemBinding) e.getProblem(); } if (data.problem != null) return data.problem; // 3: resolve ambiguities IBinding binding; try { binding = resolveAmbiguities(data, name); } catch (DOMException e) { binding = e.getProblem(); } // 4: post processing binding = postResolution(binding, data); if (traceBindingResolution) { traceIndent--; for (int i = 0; i < traceIndent; i++) System.out.print(" "); //$NON-NLS-1$ System.out.println("Resolved " + name + ':' + ((ASTNode) name).getOffset() + //$NON-NLS-1$ " to " + DebugUtil.toStringWithClass(binding) + ':' + System.identityHashCode(binding)); //$NON-NLS-1$ } return binding; } protected static IBinding postResolution(IBinding binding, IASTName name) { LookupData data = createLookupData(name); return postResolution(binding, data); } private static IBinding postResolution(IBinding binding, LookupData data) { if (binding instanceof IProblemBinding) return binding; if (binding == null && data.checkClassContainingFriend()) { // 3.4.1-10 if we don't find a name used in a friend declaration in the member declaration's class // we should look in the class granting friendship IASTNode parent = data.astName.getParent(); while (parent != null && !(parent instanceof ICPPASTCompositeTypeSpecifier)) parent = parent.getParent(); if (parent instanceof ICPPASTCompositeTypeSpecifier) { IScope scope = ((ICPPASTCompositeTypeSpecifier) parent).getScope(); try { lookup(data, scope); binding = resolveAmbiguities(data, data.astName); } catch (DOMException e) { binding = e.getProblem(); } } } // Explicit type conversion in functional notation if (binding instanceof ICPPClassTemplate && data.astName instanceof ICPPASTTemplateId) { final IASTNode parent = data.astName.getParent(); if (parent instanceof IASTIdExpression && parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { return binding; } } /* 14.6.1-1: * Within the scope of a class template, when the name of the template is neither qualified nor * followed by <, it is equivalent to the name followed by the template parameters enclosed in <>. */ if (binding instanceof ICPPClassTemplate && !(binding instanceof ICPPClassSpecialization) && !(binding instanceof ICPPTemplateParameter) && !(data.astName instanceof ICPPASTTemplateId)) { ASTNodeProperty prop = data.astName.getPropertyInParent(); if (prop != ICPPASTTemplateId.TEMPLATE_NAME && prop != ICPPASTQualifiedName.SEGMENT_NAME) { // You cannot use a class template name outside of the class template scope, // mark it as a problem. IBinding replacement= CPPTemplates.isUsedInClassTemplateScope((ICPPClassTemplate) binding, data.astName); if (replacement != null) { binding= replacement; } else { boolean ok= false; IASTNode node= data.astName.getParent(); while (node != null && !ok) { if (node instanceof ICPPASTTemplateId || node instanceof ICPPASTTemplatedTypeTemplateParameter) { ok= true; // can be argument or default-value for template template parameter break; } else if (node instanceof IASTElaboratedTypeSpecifier) { IASTNode parent= node.getParent(); if (parent instanceof IASTSimpleDeclaration) { IASTDeclSpecifier declspec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); if (declspec instanceof ICPPASTDeclSpecifier) { if (((ICPPASTDeclSpecifier) declspec).isFriend()) { ok= true; // a friend class template declarations uses resolution. break; } } } } node= node.getParent(); } if (!ok) { binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } } } } else if (binding instanceof ICPPDeferredClassInstance) { // try to replace binding by the one pointing to the enclosing template declaration. ICPPDeferredClassInstance dcl= (ICPPDeferredClassInstance) binding; IBinding usedHere= CPPTemplates.isUsedInClassTemplateScope(dcl.getClassTemplate(), data.astName); if (usedHere instanceof ICPPDeferredClassInstance) { ICPPDeferredClassInstance alt= (ICPPDeferredClassInstance) usedHere; if (CPPTemplates.areSameArguments(alt.getTemplateArguments(), dcl.getTemplateArguments())) { binding= alt; } } } if (binding instanceof IType) { IType t = getNestedType((IType) binding, TDEF); if (t instanceof ICPPClassType && convertClassToConstructor(data.astName)) { ICPPClassType cls= (ICPPClassType) t; if (cls instanceof IIndexBinding) { cls= data.tu.mapToAST(cls); } try { if (data.astName instanceof ICPPASTTemplateId && cls instanceof ICPPClassTemplate) { if (data.tu != null) { ICPPASTTemplateId id = (ICPPASTTemplateId) data.astName; ICPPTemplateArgument[] args = CPPTemplates.createTemplateArgumentArray(id); IBinding inst= CPPTemplates.instantiate((ICPPClassTemplate) cls, args); if (inst instanceof ICPPClassType) { cls= (ICPPClassType) inst; } } } if (cls instanceof ICPPUnknownBinding) { binding= new CPPUnknownConstructor(cls); } else { binding= CPPSemantics.resolveFunction(data, cls.getConstructors(), true); } } catch (DOMException e) { return e.getProblem(); } } } IASTName name= data.astName; IASTNode nameParent= name.getParent(); if (nameParent instanceof ICPPASTTemplateId) { if (binding instanceof ICPPTemplateInstance) { final ICPPTemplateInstance instance = (ICPPTemplateInstance) binding; binding = instance.getSpecializedBinding(); name.setBinding(binding); ((ICPPASTTemplateId) nameParent).setBinding(instance); } name= (ICPPASTTemplateId) nameParent; nameParent= name.getParent(); } if (nameParent instanceof ICPPASTQualifiedName) { if (name == ((ICPPASTQualifiedName) nameParent).getLastName()) { name= (IASTName) nameParent; nameParent= name.getParent(); } } // if the lookup in base-classes ran into a deferred instance, use the computed unknown binding. final ASTNodeProperty namePropertyInParent = name.getPropertyInParent(); if (binding == null && data.skippedScope != null) { if (data.hasFunctionArguments()) { binding= new CPPUnknownFunction(data.skippedScope, name.getSimpleID()); } else { if (namePropertyInParent == IASTNamedTypeSpecifier.NAME) { binding= new CPPUnknownClass(data.skippedScope, name.getSimpleID()); } else { binding= new CPPUnknownBinding(data.skippedScope, name.getSimpleID()); } } } if (binding != null) { if (namePropertyInParent == IASTNamedTypeSpecifier.NAME) { if (!(binding instanceof IType || binding instanceof ICPPConstructor)) { IASTNode parent = name.getParent().getParent(); if (parent instanceof IASTTypeId && parent.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) { if (!(binding instanceof IType)) { // a type id needs to hold a type binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } // don't create a problem here } else { binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } } } else if (namePropertyInParent == IASTIdExpression.ID_NAME) { if (binding instanceof IType) { final IASTNode idExpr = name.getParent(); ASTNodeProperty pip = idExpr.getPropertyInParent(); if (pip == ICPPASTTemplatedTypeTemplateParameter.DEFAULT_VALUE) { // Default for template template parameter is a type. } else if (pip == IASTFunctionCallExpression.FUNCTION_NAME) { // Explicit type conversion in functional notation. } else if (pip == IASTUnaryExpression.OPERAND && ((ICPPASTUnaryExpression) idExpr.getParent()).getOperator() == IASTUnaryExpression.op_sizeofParameterPack) { // Argument of sizeof... can be a type } else { binding= new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } } } } // Some declarations are found via name resolution (e.g. when using a qualified name), // add name as definition and check the declaration specifier. final IASTDeclaration declaration = data.forDeclaration(); if (declaration != null) { // Functions if (binding instanceof IFunction) { binding= checkDeclSpecifier(binding, data.astName, declaration); if (!(binding instanceof IProblemBinding)) { if (declaration instanceof ICPPASTFunctionDefinition) { ASTInternal.addDefinition(binding, data.astName); } } } // Definitions of static fields. if (binding instanceof ICPPField && data.astName.isDefinition()) { if (declaration.getPropertyInParent() != IASTCompositeTypeSpecifier.MEMBER_DECLARATION) { ASTInternal.addDefinition(binding, data.astName); } } } // If we're still null... if (binding == null) { if (name instanceof ICPPASTQualifiedName && declaration != null) { binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_MEMBER_DECLARATION_NOT_FOUND, data.getFoundBindings()); } else { binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, data.getFoundBindings()); } } return binding; } private static boolean convertClassToConstructor(IASTName name) { if (name == null) return false; final ASTNodeProperty propertyInParent = name.getPropertyInParent(); if (propertyInParent == CPPSemantics.STRING_LOOKUP_PROPERTY || propertyInParent == null) return false; if (propertyInParent == ICPPASTTemplateId.TEMPLATE_NAME) return false; IASTNode parent= name.getParent(); if (parent instanceof ICPPASTQualifiedName) { if (((ICPPASTQualifiedName) parent).getLastName() != name) return false; parent= parent.getParent(); } if (parent instanceof ICPPASTConstructorChainInitializer) { return true; } if (parent instanceof ICPPASTNamedTypeSpecifier) { parent= parent.getParent(); if (parent instanceof IASTTypeId && parent.getParent() instanceof ICPPASTNewExpression) { IASTDeclarator dtor = ((IASTTypeId) parent).getAbstractDeclarator(); if (dtor != null && dtor.getPointerOperators().length == 0) return true; } } return false; } private static void doKoenigLookup(LookupData data) throws DOMException { data.ignoreUsingDirectives = true; data.forceQualified = true; Set<ICPPNamespaceScope> associated = getAssociatedScopes(data); for (ICPPNamespaceScope scope : associated) { if (!data.visited.containsKey(scope)) { lookup(data, scope); } } } static IBinding checkDeclSpecifier(IBinding binding, IASTName name, IASTNode decl) { // check for empty declaration specifiers if (!isCtorOrConversionOperator(binding)) { IASTDeclSpecifier declspec= null; if (decl instanceof IASTSimpleDeclaration) { declspec= ((IASTSimpleDeclaration) decl).getDeclSpecifier(); } else if (decl instanceof IASTFunctionDefinition) { declspec= ((IASTFunctionDefinition) decl).getDeclSpecifier(); } if (declspec != null && CPPVisitor.doesNotSpecifyType(declspec)) { binding= new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_TYPE); } } return binding; } private static boolean isCtorOrConversionOperator(IBinding binding) { if (binding instanceof ICPPConstructor) return true; if (binding instanceof ICPPMethod) { ICPPMethod m= (ICPPMethod) binding; if (m.isDestructor()) return true; return isConversionOperator(m); } return false; } public static LookupData createLookupData(IASTName name) { LookupData data = new LookupData(name); IASTNode parent = name.getParent(); if (parent instanceof ICPPASTTemplateId) parent = parent.getParent(); if (parent instanceof ICPPASTQualifiedName) parent = parent.getParent(); if (parent instanceof IASTDeclarator && parent.getPropertyInParent() == IASTSimpleDeclaration.DECLARATOR) { IASTSimpleDeclaration simple = (IASTSimpleDeclaration) parent.getParent(); if (simple.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef) data.forceQualified = true; } if (parent instanceof IASTIdExpression) { IASTNode grand= parent.getParent(); while (grand instanceof IASTUnaryExpression && ((IASTUnaryExpression) grand).getOperator() == IASTUnaryExpression.op_bracketedPrimary) { parent= grand; grand = grand.getParent(); } if (parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { parent = parent.getParent(); IASTInitializerClause[] args = ((IASTFunctionCallExpression) parent).getArguments(); data.setFunctionArguments(false, args); } } else if (parent instanceof ICPPASTFieldReference) { IASTNode grand= parent.getParent(); while (grand instanceof IASTUnaryExpression && ((IASTUnaryExpression) grand).getOperator() == IASTUnaryExpression.op_bracketedPrimary) { parent= grand; grand = grand.getParent(); } if (parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { IASTInitializerClause[] exp = ((IASTFunctionCallExpression) parent.getParent()).getArguments(); data.setFunctionArguments(false, exp); } } else if (parent instanceof ICPPASTNamedTypeSpecifier && parent.getParent() instanceof IASTTypeId) { IASTTypeId typeId = (IASTTypeId) parent.getParent(); if (typeId.getParent() instanceof ICPPASTNewExpression) { ICPPASTNewExpression newExp = (ICPPASTNewExpression) typeId.getParent(); IASTInitializer init = newExp.getInitializer(); if (init == null) { data.setFunctionArguments(false); } else if (init instanceof ICPPASTConstructorInitializer) { data.setFunctionArguments(false, ((ICPPASTConstructorInitializer) init).getArguments()); } else if (init instanceof ICPPASTInitializerList) { data.setFunctionArguments(false, (ICPPASTInitializerList) init); } } } else if (parent instanceof ICPPASTConstructorChainInitializer) { ICPPASTConstructorChainInitializer ctorinit = (ICPPASTConstructorChainInitializer) parent; IASTInitializer init = ctorinit.getInitializer(); if (init instanceof ICPPASTConstructorInitializer) { data.setFunctionArguments(false, ((ICPPASTConstructorInitializer) init).getArguments()); } else if (init instanceof ICPPASTInitializerList) { data.setFunctionArguments(false, (ICPPASTInitializerList) init); } } return data; } private static Set<ICPPNamespaceScope> getAssociatedScopes(LookupData data) { if (!data.hasFunctionArguments()) return Collections.emptySet(); IType[] ps = data.getFunctionArgumentTypes(); Set<ICPPNamespaceScope> namespaces = new HashSet<ICPPNamespaceScope>(2); ObjectSet<IType> handled = new ObjectSet<IType>(2); for (IType p : ps) { try { getAssociatedScopes(p, namespaces, handled, data.tu); } catch (DOMException e) { } } if (data.astName != null && CharArrayUtils.equals(CPPVisitor.BEGIN, data.astName.getSimpleID())) { IASTNode parent = data.astName.getParent(); // id-expression if (parent != null) parent= parent.getParent(); // function call if (parent != null) parent= parent.getParent(); // the loop if (parent != null) parent= parent.getParent(); // unary * if (parent instanceof ICPPASTRangeBasedForStatement) { IBinding[] std= parent.getTranslationUnit().getScope().find(CPPVisitor.STD); for (IBinding binding : std) { if (binding instanceof ICPPNamespace) { namespaces.add(((ICPPNamespace) binding).getNamespaceScope()); } } } } return namespaces; } // 3.4.2-2 private static void getAssociatedScopes(IType t, Set<ICPPNamespaceScope> namespaces, ObjectSet<IType> handled, CPPASTTranslationUnit tu) throws DOMException { t = getNestedType(t, TDEF | CVTYPE | PTR | ARRAY | REF); if (t instanceof IBinding) { if (handled.containsKey(t)) return; handled.put(t); IBinding owner= ((IBinding) t).getOwner(); if (owner instanceof ICPPClassType) { getAssociatedScopes((IType) owner, namespaces, handled, tu); } else { getAssociatedNamespaceScopes(getContainingNamespaceScope((IBinding) t, tu), namespaces); } } if (t instanceof ICPPClassType && !(t instanceof ICPPClassTemplate)) { ICPPClassType ct= (ICPPClassType) t; ICPPBase[] bases = ct.getBases(); for (ICPPBase base : bases) { IBinding b = base.getBaseClass(); if (b instanceof IType) getAssociatedScopes((IType) b, namespaces, handled, tu); } // Furthermore, if T is a class template ... // * ... types of the template arguments for template type parameters // (excluding template template parameters); // * ... owners of which any template template arguments are members; if (ct instanceof ICPPTemplateInstance) { ICPPTemplateArgument[] args = ((ICPPTemplateInstance) ct).getTemplateArguments(); for (ICPPTemplateArgument arg : args) { if (arg.isTypeValue()) { getAssociatedScopes(arg.getTypeValue(), namespaces, handled, tu); } } } } else if (t instanceof IFunctionType) { IFunctionType ft = (IFunctionType) t; getAssociatedScopes(ft.getReturnType(), namespaces, handled, tu); IType[] ps = ft.getParameterTypes(); for (IType pt : ps) { getAssociatedScopes(pt, namespaces, handled, tu); } } else if (t instanceof ICPPPointerToMemberType) { final ICPPPointerToMemberType pmt = (ICPPPointerToMemberType) t; getAssociatedScopes(pmt.getMemberOfClass(), namespaces, handled, tu); getAssociatedScopes(pmt.getType(), namespaces, handled, tu); } else if (t instanceof FunctionSetType) { FunctionSetType fst= (FunctionSetType) t; for (ICPPFunction fn : fst.getFunctionSet()) { getAssociatedScopes(fn.getType(), namespaces, handled, tu); } } } private static ICPPNamespaceScope getContainingNamespaceScope(IBinding binding, CPPASTTranslationUnit tu) throws DOMException { if (binding == null) return null; IScope scope = binding.getScope(); if (scope instanceof IIndexScope) { scope= tu.mapToASTScope((IIndexScope) scope); } while (scope != null && !(scope instanceof ICPPNamespaceScope)) { scope = getParentScope(scope, tu); } return (ICPPNamespaceScope) scope; } public static void getAssociatedNamespaceScopes(ICPPNamespaceScope scope, Set<ICPPNamespaceScope> namespaces) { if (scope == null || !namespaces.add(scope)) return; if (scope instanceof ICPPInternalNamespaceScope) { final ICPPInternalNamespaceScope internalScope = (ICPPInternalNamespaceScope) scope; for (ICPPNamespaceScope mem : internalScope.getEnclosingNamespaceSet()) { namespaces.add(mem); } } } static ICPPScope getLookupScope(IASTName name, LookupData data) throws DOMException { IASTNode parent = name.getParent(); IScope scope = null; if (parent instanceof ICPPASTBaseSpecifier) { ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) parent.getParent(); IASTName n = compSpec.getName(); if (n instanceof ICPPASTQualifiedName) { n = ((ICPPASTQualifiedName) n).getLastName(); } scope = CPPVisitor.getContainingScope(n); } else { scope = CPPVisitor.getContainingScope(name, data); } if (scope instanceof ICPPScope) { return (ICPPScope) scope; } else if (scope instanceof IProblemBinding) { return new CPPScope.CPPScopeProblem(((IProblemBinding) scope).getASTNode(), IProblemBinding.SEMANTIC_BAD_SCOPE, ((IProblemBinding) scope).getNameCharArray()); } return new CPPScope.CPPScopeProblem(name, IProblemBinding.SEMANTIC_BAD_SCOPE); } private static void mergeResults(LookupData data, Object results, boolean scoped) { if (!data.contentAssist) { if (results instanceof IBinding) { data.foundItems = ArrayUtil.append(Object.class, (Object[]) data.foundItems, results); } else if (results instanceof Object[]) { data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results); } } else { data.foundItems = mergePrefixResults((CharArrayObjectMap) data.foundItems, results, scoped); } } /** * @param dest * @param source : either Object[] or CharArrayObjectMap * @param scoped * @return */ static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) { if (source == null) return dest; CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2); CharArrayObjectMap map = null; Object[] objs = null; int size; if (source instanceof CharArrayObjectMap) { map = (CharArrayObjectMap) source; size= map.size(); } else { if (source instanceof Object[]) objs = ArrayUtil.trim(Object.class, (Object[]) source); else objs = new Object[]{ source }; size= objs.length; } int resultInitialSize = resultMap.size(); for (int i = 0; i < size; i ++) { char[] key; Object so; if (map != null) { key= map.keyAt(i); so= map.get(key); } else if (objs != null) { so= objs[i]; key= (so instanceof IBinding) ? ((IBinding) so).getNameCharArray() : ((IASTName) so).getSimpleID(); } else { return resultMap; } int idx = resultMap.lookup(key); if (idx == -1) { resultMap.put(key, so); } else if (!scoped || idx >= resultInitialSize) { Object obj = resultMap.get(key); if (obj instanceof Object[]) { if (so instanceof IBinding || so instanceof IASTName) obj = ArrayUtil.append(Object.class, (Object[]) obj, so); else obj = ArrayUtil.addAll(Object.class, (Object[]) obj, (Object[]) so); } else { if (so instanceof IBinding || so instanceof IASTName) { obj = new Object[] { obj, so }; } else { Object[] temp = new Object[((Object[]) so).length + 1]; temp[0] = obj; obj = ArrayUtil.addAll(Object.class, temp, (Object[]) so); } } resultMap.put(key, obj); } } return resultMap; } private static IIndexFileSet getIndexFileSet(LookupData data) { if (data.tu != null) { final IIndexFileSet fs= data.tu.getIndexFileSet(); if (fs != null) return fs; } return IIndexFileSet.EMPTY; } /** * Perform a lookup with the given data starting in the given scope, considering bases and parent scopes. * @param data the lookup data created off a name * @param start either a scope or a name. */ static protected void lookup(LookupData data, IScope start) throws DOMException { if (data.astName == null) return; if (start == null && lookupDestructor(data, start)) { return; } ICPPScope nextScope= null; ICPPTemplateScope nextTmplScope= null; if (start instanceof ICPPScope) { nextScope= (ICPPScope) start; } else { nextScope= getLookupScope(data.astName, data); if (nextScope instanceof ICPPTemplateScope) { nextTmplScope= (ICPPTemplateScope) nextScope; nextScope= getParentScope(nextScope, data.tu); } else { nextTmplScope= enclosingTemplateScope(data.astName); } if (!data.usesEnclosingScope && nextTmplScope != null) { nextTmplScope= null; if (dependsOnTemplateFieldReference(data.astName)) { data.checkPointOfDecl= false; } } } if (nextScope == null) return; boolean friendInLocalClass = false; if (nextScope instanceof ICPPClassScope && data.forFriendship()) { try { ICPPClassType cls = ((ICPPClassScope) nextScope).getClassType(); friendInLocalClass = !cls.isGloballyQualified(); } catch (DOMException e) { } } final IIndexFileSet fileSet= getIndexFileSet(data); while (nextScope != null || nextTmplScope != null) { // when the non-template scope is no longer contained within the first template scope, // we use the template scope for the next iteration. boolean useTemplScope= false; if (nextTmplScope != null) { useTemplScope= true; if (nextScope instanceof IASTInternalScope) { final IASTNode node= ((IASTInternalScope) nextScope).getPhysicalNode(); if (node != null && nextTmplScope.getTemplateDeclaration().contains(node)) { useTemplScope= false; } } } ICPPScope scope= useTemplScope ? nextTmplScope : nextScope; if (scope instanceof IIndexScope && data.tu != null) { scope= (ICPPScope) data.tu.mapToASTScope(((IIndexScope) scope)); } if (!data.usingDirectivesOnly && !(data.ignoreMembers && scope instanceof ICPPClassScope)) { mergeResults(data, getBindingsFromScope(scope, fileSet, data), true); // Nominate using-directives found in this block or namespace. if (scope instanceof ICPPNamespaceScope) { final ICPPNamespaceScope blockScope= (ICPPNamespaceScope) scope; if (data.qualified() && blockScope.getKind() != EScopeKind.eLocal) { lookupInlineNamespaces(data, fileSet, blockScope); } if (data.contentAssist || !data.hasResults() || !data.qualified()) { // Nominate namespaces nominateNamespaces(data, blockScope); } } } // Lookup in nominated namespaces if (!data.ignoreUsingDirectives && scope instanceof ICPPNamespaceScope && !(scope instanceof ICPPBlockScope)) { if (!data.hasResults() || !data.qualified() || data.contentAssist) { lookupInNominated(data, fileSet, (ICPPNamespaceScope) scope); } } if (friendInLocalClass && !(scope instanceof ICPPClassScope)) return; if (!data.contentAssist && hasReachableResult(data)) return; // Lookup in base classes if (!data.usingDirectivesOnly && scope instanceof ICPPClassScope && !data.ignoreMembers) { BaseClassLookup.lookupInBaseClasses(data, (ICPPClassScope) scope, fileSet); if (!data.contentAssist && data.hasResultOrProblem()) return; } if (data.qualified() && !(scope instanceof ICPPTemplateScope)) { if (data.ignoreUsingDirectives || data.usingDirectives.isEmpty()) return; data.usingDirectivesOnly = true; } // Compute next scopes if (useTemplScope && nextTmplScope != null) { nextTmplScope= enclosingTemplateScope(nextTmplScope.getTemplateDeclaration()); } else { nextScope= getParentScope(scope, data.tu); } } } /** * Checks if lookup data contains result bindings reachable through includes * from the translation unit where lookup started. Any binding is considered reachable * if the lookup is not done in a context of a translation unit. * * @param data the LookupData object. * @return {@code true} if the lookup data contains at least one reachable binding. */ private static boolean hasReachableResult(LookupData data) { if (data.foundItems instanceof Object[]) { for (Object item : (Object[]) data.foundItems) { if (item instanceof IBinding) { IBinding binding = (IBinding) item; if (!isFromIndex(binding) || data.tu == null || isReachableFromAst(data.tu, binding)) { return true; } } } } return false; } private static void lookupInlineNamespaces(LookupData data, IIndexFileSet fileSet, ICPPNamespaceScope namespace) throws DOMException { if (namespace instanceof ICPPInternalNamespaceScope) { ICPPInternalNamespaceScope ns= (ICPPInternalNamespaceScope) namespace; for (ICPPInternalNamespaceScope inline : ns.getInlineNamespaces()) { mergeResults(data, getBindingsFromScope(inline, fileSet, data), true); lookupInlineNamespaces(data, fileSet, inline); nominateNamespaces(data, inline); } } } private static void nominateNamespaces(LookupData data, final ICPPNamespaceScope blockScope) throws DOMException { final boolean isBlockScope = blockScope.getKind() == EScopeKind.eLocal; if (!isBlockScope) { data.visited.put(blockScope); // Mark as searched. if (data.tu != null) { data.tu.handleAdditionalDirectives(blockScope); } } ICPPUsingDirective[] uds= blockScope.getUsingDirectives(); if (uds != null && uds.length > 0) { HashSet<ICPPNamespaceScope> handled= new HashSet<ICPPNamespaceScope>(); for (final ICPPUsingDirective ud : uds) { if (declaredBefore(ud, data.astName, false)) { storeUsingDirective(data, blockScope, ud, handled); } } } } private static boolean lookupDestructor(LookupData data, IScope start) throws DOMException { IASTName typeDtorName= data.astName; final char[] typeDtorChars= typeDtorName.getSimpleID(); if (typeDtorChars.length == 0 || typeDtorChars[0] != '~') return false; // Assume class C; typedef C T; // When looking up ~T the strategy is to lookup T::~C in two steps: // * First resolve 'T', then compute '~C' and resolve it. CPPASTQualifiedName syntheticName= new CPPASTQualifiedName(); IASTNode parent= typeDtorName.getParent(); if (parent instanceof ICPPASTQualifiedName) { ICPPASTQualifiedName dqname= (ICPPASTQualifiedName) parent; if (dqname.getLastName() != data) return false; syntheticName.setFullyQualified(dqname.isFullyQualified()); IASTName[] children = dqname.getNames(); for (IASTName child : children) { if (child != data) { final IASTName childCopy = child.copy(); childCopy.setBinding(child.resolveBinding()); syntheticName.addName(childCopy); } } syntheticName.setOffsetAndLength((ASTNode) parent); syntheticName.setParent(parent.getParent()); syntheticName.setPropertyInParent(parent.getPropertyInParent()); } else { syntheticName.setOffsetAndLength((ASTNode) typeDtorName); syntheticName.setParent(parent); syntheticName.setPropertyInParent(typeDtorName.getPropertyInParent()); } char[] tchars= new char[typeDtorChars.length-1]; System.arraycopy(typeDtorChars, 1, tchars, 0, tchars.length); final CPPASTName typeName = new CPPASTName(tchars); typeName.setOffsetAndLength((ASTNode) typeDtorName); syntheticName.addName(typeName); final CPPASTName classDtorName = new CPPASTName(typeDtorChars); classDtorName.setOffsetAndLength((ASTNode) typeDtorName); syntheticName.addName(classDtorName); IBinding type= resolveBinding(typeName); if (!(type instanceof ITypedef)) return false; IType t= SemanticUtil.getNestedType((ITypedef) type, TDEF); if (t instanceof ICPPUnknownBinding || t instanceof ISemanticProblem || !(t instanceof ICPPClassType)) { return false; } ICPPClassType classType= (ICPPClassType) t; final IScope scope = ((ICPPClassType) t).getCompositeScope(); if (scope == null) { return false; } char[] classChars= classType.getNameCharArray(); char[] classDtorChars= new char[classChars.length+1]; classDtorChars[0]= '~'; System.arraycopy(classChars, 0, classDtorChars, 1, classChars.length); classDtorName.setName(classDtorChars); data.astName = classDtorName; try { lookup(data, scope); } finally { data.astName= typeDtorName; } return true; } /** * Checks whether the name directly or indirectly depends on the this pointer. */ private static boolean dependsOnTemplateFieldReference(IASTName astName) { if (astName.getPropertyInParent() != IASTFieldReference.FIELD_NAME) return false; final boolean[] result= {false}; final IASTExpression fieldOwner = ((IASTFieldReference) astName.getParent()).getFieldOwner(); fieldOwner.accept(new ASTVisitor() { { shouldVisitNames= true; shouldVisitExpressions= true; } @Override public int visit(IASTName name) { IBinding b= name.resolvePreBinding(); if (b instanceof ICPPUnknownBinding || b instanceof ICPPTemplateDefinition) { result[0]= true; return PROCESS_ABORT; } if (b instanceof ICPPMember) { ICPPMember mem= (ICPPMember) b; if (!mem.isStatic()) { ICPPClassType owner= mem.getClassOwner(); if (owner instanceof ICPPUnknownBinding || owner instanceof ICPPTemplateDefinition) { result[0]= true; return PROCESS_ABORT; } } } if (b instanceof IVariable) { IType t= SemanticUtil.getUltimateType(((IVariable) b).getType(), true); if (t instanceof ICPPUnknownBinding || t instanceof ICPPTemplateDefinition) { result[0]= true; return PROCESS_ABORT; } } if (name instanceof ICPPASTTemplateId) return PROCESS_SKIP; return PROCESS_CONTINUE; } @Override public int visit(IASTExpression expression) { if (expression instanceof IASTLiteralExpression) { if (((IASTLiteralExpression) expression).getKind() == IASTLiteralExpression.lk_this) { final IType thisType = SemanticUtil.getNestedType(typeOrFunctionSet(expression), TDEF | ALLCVQ | PTR | ARRAY | MPTR | REF); if (thisType instanceof ICPPUnknownBinding || thisType instanceof ICPPTemplateDefinition) { result[0]= true; return PROCESS_ABORT; } } } if (expression instanceof IASTUnaryExpression) { switch (((IASTUnaryExpression) expression).getOperator()) { case IASTUnaryExpression.op_sizeof: case IASTUnaryExpression.op_sizeofParameterPack: case IASTUnaryExpression.op_typeid: case IASTUnaryExpression.op_throw: return PROCESS_SKIP; } } else if (expression instanceof IASTTypeIdExpression) { switch (((IASTTypeIdExpression) expression).getOperator()) { case IASTTypeIdExpression.op_sizeof: case IASTTypeIdExpression.op_typeid: return PROCESS_SKIP; } } else if (expression instanceof IASTCastExpression) { if (!((IASTCastExpression) expression).getTypeId().accept(this)) { return PROCESS_ABORT; } return PROCESS_SKIP; } else if (expression instanceof ICPPASTNewExpression) { if (!((ICPPASTNewExpression) expression).getTypeId().accept(this)) { return PROCESS_ABORT; } return PROCESS_SKIP; } else if (expression instanceof ICPPASTSimpleTypeConstructorExpression) { return PROCESS_SKIP; } else if (expression instanceof IASTTypeIdInitializerExpression) { if (!((IASTTypeIdInitializerExpression) expression).getTypeId().accept(this)) { return PROCESS_ABORT; } return PROCESS_SKIP; } return PROCESS_CONTINUE; } }); return result[0]; } static IBinding[] getBindingsFromScope(ICPPScope scope, final IIndexFileSet fileSet, LookupData data) throws DOMException { IBinding[] bindings; // For internal scopes we need to check the point of declaration if (scope instanceof ICPPASTInternalScope) { final IASTName astName = data.astName; final ICPPASTInternalScope internalScope = (ICPPASTInternalScope) scope; bindings= internalScope.getBindings(astName, true, data.prefixLookup, fileSet, data.checkPointOfDecl); // Bug 103857: Members declared after the point of completion cannot be // found in the partial AST, we look them up in the index if (data.checkWholeClassScope && scope instanceof ICPPClassScope) { final IASTTranslationUnit tu = astName.getTranslationUnit(); if (tu instanceof ASTTranslationUnit && ((ASTTranslationUnit) tu).isForContentAssist()) { IIndex index = tu.getIndex(); IASTNode node = internalScope.getPhysicalNode(); if (index != null && node != null && node.contains(astName)) { IBinding indexBinding= index.adaptBinding(((ICPPClassScope) scope).getClassType()); if (indexBinding instanceof ICPPClassType) { IScope scopeInIndex= ((ICPPClassType) indexBinding).getCompositeScope(); bindings= ArrayUtil.addAll(bindings, scopeInIndex.getBindings(astName, true, data.prefixLookup, fileSet)); } } } } } else { // For index scopes the point of declaration is ignored. bindings= scope.getBindings(data.astName, true, data.prefixLookup, fileSet); } return expandUsingDeclarationsAndRemoveObjects(bindings, data.typesOnly); } private static IBinding[] expandUsingDeclarationsAndRemoveObjects(final IBinding[] bindings, boolean removeObjects) { if (bindings == null || bindings.length == 0) return IBinding.EMPTY_BINDING_ARRAY; for (IBinding b : bindings) { if (b == null) break; if (b instanceof ICPPUsingDeclaration || (removeObjects && isObject(b))) { List<IBinding> result= new ArrayList<IBinding>(bindings.length); expandUsingDeclarations(bindings, removeObjects, result); return result.toArray(new IBinding[result.size()]); } } return bindings; } private static boolean isObject(IBinding b) { return !(b instanceof IType || b instanceof ICPPNamespace); } private static void expandUsingDeclarations(IBinding[] bindings, boolean removeObjects, List<IBinding> result) { if (bindings != null) { for (IBinding b : bindings) { if (b == null) return; if (b instanceof ICPPUsingDeclaration) { for (IBinding d : ((ICPPUsingDeclaration) b).getDelegates()) { if (d != null && !(removeObjects && isObject(d))) { result.add(d); } } } else if (!(removeObjects && isObject(b))) { result.add(b); } } } } private static ICPPTemplateScope enclosingTemplateScope(IASTNode node) { IASTNode parent= node.getParent(); if (parent instanceof IASTName) { if (parent instanceof ICPPASTTemplateId) { node= parent; parent= node.getParent(); } if (parent instanceof ICPPASTQualifiedName) { ICPPASTQualifiedName qname= (ICPPASTQualifiedName) parent; if (qname.isFullyQualified() || qname.getNames()[0] != node) return null; } } while (!(parent instanceof ICPPASTTemplateDeclaration)) { if (parent == null) return null; parent= parent.getParent(); } return ((ICPPASTTemplateDeclaration) parent).getScope(); } static ICPPScope getParentScope(IScope scope, CPPASTTranslationUnit unit) throws DOMException { IScope parentScope= scope.getParent(); // the index cannot return the translation unit as parent scope if (unit != null) { if (parentScope == null && (scope instanceof IIndexScope || scope instanceof ICPPClassSpecializationScope)) { parentScope = unit.getScope(); } else if (parentScope instanceof IIndexScope) { parentScope = unit.mapToASTScope((IIndexScope) parentScope); } } return (ICPPScope) parentScope; } /** * Stores the using directive with the scope where the members of the nominated namespace will appear. * In case of an unqualified lookup the transitive directives are stored, also. This is important because * the members nominated by a transitive directive can appear before those of the original directive. */ private static void storeUsingDirective(LookupData data, ICPPNamespaceScope container, ICPPUsingDirective directive, Set<ICPPNamespaceScope> handled) throws DOMException { ICPPNamespaceScope nominated= directive.getNominatedScope(); if (nominated instanceof IIndexScope && data.tu != null) { nominated= (ICPPNamespaceScope) data.tu.mapToASTScope((IIndexScope) nominated); } if (nominated == null || data.visited.containsKey(nominated) || (handled != null && !handled.add(nominated))) { return; } // 7.3.4.1 names appear at end of common enclosing scope of container and nominated scope. final IScope appearsIn= getCommonEnclosingScope(nominated, container, data.tu); if (appearsIn instanceof ICPPNamespaceScope) { // store the directive with the scope where it has to be considered List<ICPPNamespaceScope> listOfNominated= data.usingDirectives.get(appearsIn); if (listOfNominated == null) { listOfNominated= new ArrayList<ICPPNamespaceScope>(1); if (data.usingDirectives.isEmpty()) { data.usingDirectives= new HashMap<ICPPNamespaceScope, List<ICPPNamespaceScope>>(); } data.usingDirectives.put((ICPPNamespaceScope) appearsIn, listOfNominated); } listOfNominated.add(nominated); } // in a non-qualified lookup the transitive directive have to be stored right away, they may overtake the // container. if (!data.qualified() || data.contentAssist) { assert handled != null; if (data.tu != null) { data.tu.handleAdditionalDirectives(nominated); } ICPPUsingDirective[] transitive= nominated.getUsingDirectives(); for (ICPPUsingDirective element : transitive) { storeUsingDirective(data, container, element, handled); } } } /** * Computes the common enclosing scope of s1 and s2. */ private static ICPPScope getCommonEnclosingScope(IScope s1, IScope s2, CPPASTTranslationUnit tu) throws DOMException { ObjectSet<IScope> set = new ObjectSet<IScope>(2); IScope parent= s1; while (parent != null) { set.put(parent); parent= getParentScope(parent, tu); } parent= s2; while (parent != null && !set.containsKey(parent)) { parent = getParentScope(parent, tu); } return (ICPPScope) parent; } public static void populateCache(ICPPASTInternalScope scope) { IASTNode[] nodes = null; IASTNode parent= ASTInternal.getPhysicalNodeOfScope(scope); IASTName[] namespaceDefs = null; int namespaceIdx = -1; if (parent instanceof IASTCompoundStatement) { IASTNode p = parent.getParent(); if (p instanceof IASTFunctionDefinition) { ICPPASTFunctionDeclarator dtor = (ICPPASTFunctionDeclarator) ((IASTFunctionDefinition) p).getDeclarator(); nodes = dtor.getParameters(); } else if (p instanceof ICPPASTLambdaExpression) { ICPPASTFunctionDeclarator dtor = ((ICPPASTLambdaExpression) p).getDeclarator(); if (dtor != null) { nodes = dtor.getParameters(); } } if (p instanceof ICPPASTCatchHandler) { parent = p; } else if (nodes == null || nodes.length == 0) { IASTCompoundStatement compound = (IASTCompoundStatement) parent; nodes = compound.getStatements(); } } else if (parent instanceof IASTTranslationUnit) { IASTTranslationUnit translation = (IASTTranslationUnit) parent; nodes = translation.getDeclarations(); } else if (parent instanceof ICPPASTCompositeTypeSpecifier) { ICPPASTCompositeTypeSpecifier comp = (ICPPASTCompositeTypeSpecifier) parent; nodes = comp.getMembers(); } else if (parent instanceof ICPPASTNamespaceDefinition) { // need binding because namespaces can be split CPPNamespace namespace = (CPPNamespace) ((ICPPASTNamespaceDefinition) parent).getName().resolveBinding(); namespaceDefs = namespace.getNamespaceDefinitions(); nodes = ((ICPPASTNamespaceDefinition) namespaceDefs[++namespaceIdx].getParent()).getDeclarations(); while (nodes.length == 0 && ++namespaceIdx < namespaceDefs.length) { nodes= ((ICPPASTNamespaceDefinition) namespaceDefs[namespaceIdx].getParent()).getDeclarations(); } } else if (parent instanceof ICPPASTFunctionDeclarator) { ICPPASTFunctionDeclarator dtor = (ICPPASTFunctionDeclarator) parent; nodes = dtor.getParameters(); } else if (parent instanceof ICPPASTTemplateDeclaration) { ICPPASTTemplateDeclaration template = (ICPPASTTemplateDeclaration) parent; nodes = template.getTemplateParameters(); } else if (parent instanceof ICPPASTForStatement) { ICPPASTForStatement forStatement = (ICPPASTForStatement) parent; final IASTDeclaration conditionDeclaration = forStatement.getConditionDeclaration(); IASTStatement initDeclaration= forStatement.getInitializerStatement(); if (conditionDeclaration != null) { nodes= new IASTNode[] {initDeclaration, conditionDeclaration}; } else { nodes= new IASTNode[] {initDeclaration}; } } else if (parent instanceof ICPPASTRangeBasedForStatement) { ICPPASTRangeBasedForStatement forStatement = (ICPPASTRangeBasedForStatement) parent; final IASTDeclaration decl = forStatement.getDeclaration(); nodes= new IASTNode[] {decl}; } else if (parent instanceof ICPPASTEnumerationSpecifier) { // The enumeration scope contains the enumeration items for (IASTEnumerator enumerator : ((ICPPASTEnumerationSpecifier) parent).getEnumerators()) { ASTInternal.addName(scope, enumerator.getName()); } return; } else if (parent instanceof ICPPASTTemplatedTypeTemplateParameter) { // The template-template parameter scope contains the parameters for (ICPPASTTemplateParameter par : ((ICPPASTTemplatedTypeTemplateParameter) parent).getTemplateParameters()) { IASTName name= CPPTemplates.getTemplateParameterName(par); if (name != null) { ASTInternal.addName(scope, name); } } return; } int idx = -1; IASTNode item = (nodes != null ? (nodes.length > 0 ? nodes[++idx] : null) : parent); IASTNode[][] nodeStack = null; int[] nodeIdxStack = null; int nodeStackPos = -1; while (item != null) { if (item instanceof ICPPASTLinkageSpecification) { IASTDeclaration[] decls = ((ICPPASTLinkageSpecification) item).getDeclarations(); if (decls != null && decls.length > 0) { nodeStack = (IASTNode[][]) ArrayUtil.append(IASTNode[].class, nodeStack, nodes); nodeIdxStack = ArrayUtil.setInt(nodeIdxStack, ++nodeStackPos, idx); nodes = ((ICPPASTLinkageSpecification) item).getDeclarations(); idx = 0; item = nodes[idx]; continue; } } while (item instanceof IASTLabelStatement) item= ((IASTLabelStatement) item).getNestedStatement(); if (item instanceof IASTDeclarationStatement) item = ((IASTDeclarationStatement) item).getDeclaration(); if (item instanceof ICPPASTUsingDirective) { if (scope instanceof ICPPNamespaceScope) { final ICPPNamespaceScope nsscope = (ICPPNamespaceScope) scope; final ICPPASTUsingDirective usingDirective = (ICPPASTUsingDirective) item; nsscope.addUsingDirective(new CPPUsingDirective(usingDirective)); } } else if (item instanceof ICPPASTNamespaceDefinition) { final ICPPASTNamespaceDefinition nsDef = (ICPPASTNamespaceDefinition) item; final boolean isUnnamed = nsDef.getName().getLookupKey().length == 0; final boolean isInline = nsDef.isInline(); if (isUnnamed || isInline) { if (scope instanceof CPPNamespaceScope) { final CPPNamespaceScope nsscope = (CPPNamespaceScope) scope; nsscope.addUsingDirective(new CPPUsingDirective(nsDef)); if (isInline) { nsscope.addInlineNamespace(nsDef); } } } if (!isUnnamed) { populateCache(scope, item); } } else { populateCache(scope, item); } if (nodes != null && ++idx < nodes.length) { item = nodes[idx]; } else { item = null; while (true) { if (namespaceDefs != null) { // check all definitions of this namespace while (++namespaceIdx < namespaceDefs.length) { nodes = ((ICPPASTNamespaceDefinition) namespaceDefs[namespaceIdx].getParent()).getDeclarations(); if (nodes.length > 0) { idx = 0; item = nodes[0]; break; } } } else if (parent instanceof IASTCompoundStatement && nodes instanceof IASTParameterDeclaration[]) { // function body, we were looking at parameters, now check the body itself IASTCompoundStatement compound = (IASTCompoundStatement) parent; nodes = compound.getStatements(); if (nodes.length > 0) { idx = 0; item = nodes[0]; break; } } else if (parent instanceof ICPPASTCatchHandler) { parent = ((ICPPASTCatchHandler) parent).getCatchBody(); if (parent instanceof IASTCompoundStatement) { nodes = ((IASTCompoundStatement) parent).getStatements(); if (nodes.length > 0) { idx = 0; item = nodes[0]; break; } } } if (item == null && nodeStack != null && nodeIdxStack != null && nodeStackPos >= 0) { nodes = nodeStack[nodeStackPos]; nodeStack[nodeStackPos] = null; idx = nodeIdxStack[nodeStackPos--]; if (++idx >= nodes.length) continue; item = nodes[idx]; } break; } } } } public static void populateCache(ICPPASTInternalScope scope, IASTNode node) { IASTDeclaration declaration = null; if (node instanceof ICPPASTTemplateDeclaration) { declaration = ((ICPPASTTemplateDeclaration) node).getDeclaration(); } else if (node instanceof IASTDeclaration) { declaration = (IASTDeclaration) node; } else if (node instanceof IASTDeclarationStatement) { declaration = ((IASTDeclarationStatement) node).getDeclaration(); } else if (node instanceof ICPPASTCatchHandler) { declaration = ((ICPPASTCatchHandler) node).getDeclaration(); } else if (node instanceof ICPPASTSwitchStatement) { declaration = ((ICPPASTSwitchStatement) node).getControllerDeclaration(); } else if (node instanceof ICPPASTIfStatement) { declaration = ((ICPPASTIfStatement) node).getConditionDeclaration(); } else if (node instanceof ICPPASTWhileStatement) { declaration = ((ICPPASTWhileStatement) node).getConditionDeclaration(); } else if (node instanceof IASTParameterDeclaration) { IASTParameterDeclaration parameterDeclaration = (IASTParameterDeclaration) node; IASTDeclarator dtor = parameterDeclaration.getDeclarator(); IASTDeclarator innermost= dtor; while (dtor != null) { if (dtor instanceof IASTAmbiguousDeclarator) return; innermost= dtor; dtor= dtor.getNestedDeclarator(); } if (innermost != null) { // could be null when content assist in the declSpec IASTName declName = innermost.getName(); ASTInternal.addName(scope, declName); return; } } else if (node instanceof ICPPASTTemplateParameter) { IASTName name = CPPTemplates.getTemplateParameterName((ICPPASTTemplateParameter) node); ASTInternal.addName(scope, name); return; } if (declaration == null || declaration instanceof ASTAmbiguousNode) { return; } if (declaration instanceof IASTSimpleDeclaration) { IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration; ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier(); IASTDeclarator[] declarators = simpleDeclaration.getDeclarators(); if (!declSpec.isFriend()) { for (IASTDeclarator declarator : declarators) { IASTDeclarator innermost= null; while (declarator != null) { if (declarator instanceof IASTAmbiguousDeclarator) { innermost= null; break; } innermost= declarator; declarator= declarator.getNestedDeclarator(); } if (innermost != null) { IASTName declaratorName = innermost.getName(); ASTInternal.addName(scope, declaratorName); } } } // Declaration specifiers defining or declaring a type IASTName specName = null; final EScopeKind scopeKind = scope.getKind(); if (declSpec instanceof IASTElaboratedTypeSpecifier) { // 3.3.1.5 Point of declaration if (!declSpec.isFriend()) { if (declarators.length == 0 || scopeKind == EScopeKind.eGlobal || scopeKind == EScopeKind.eNamespace) { specName = ((IASTElaboratedTypeSpecifier) declSpec).getName(); } } } else if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) declSpec; specName = compSpec.getName(); // Anonymous union or struct (GCC supports anonymous structs too) if (declarators.length == 0 && specName.getLookupKey().length == 0) { IASTDeclaration[] decls = compSpec.getMembers(); for (IASTDeclaration decl : decls) { populateCache(scope, decl); } } } else if (declSpec instanceof ICPPASTEnumerationSpecifier) { ICPPASTEnumerationSpecifier enumeration = (ICPPASTEnumerationSpecifier) declSpec; specName = enumeration.getName(); // Add unscoped enumerators to the enclosing scope if (!enumeration.isScoped()) { for (IASTEnumerator enumerator : enumeration.getEnumerators()) { ASTInternal.addName(scope, enumerator.getName()); } } } if (specName != null) { if (!(specName instanceof ICPPASTQualifiedName)) { ASTInternal.addName(scope, specName); } } // Collect friends and elaborated type specifiers with declarators // from nested classes if (declarators.length > 0 || declSpec instanceof ICPPASTCompositeTypeSpecifier) { switch (scopeKind) { case eLocal: case eGlobal: case eNamespace: NamespaceTypeCollector visitor = new NamespaceTypeCollector(scope); declSpec.accept(visitor); for (IASTDeclarator dtor : declarators) { dtor.accept(visitor); } break; case eEnumeration: case eClassType: case eTemplateDeclaration: break; } } } else if (declaration instanceof ICPPASTUsingDeclaration) { ICPPASTUsingDeclaration using = (ICPPASTUsingDeclaration) declaration; IASTName name = using.getName(); if (name instanceof ICPPASTQualifiedName) { name = ((ICPPASTQualifiedName) name).getLastName(); } ASTInternal.addName(scope, name); } else if (declaration instanceof ICPPASTNamespaceDefinition) { IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName(); ASTInternal.addName(scope, namespaceName); } else if (declaration instanceof ICPPASTNamespaceAlias) { IASTName alias = ((ICPPASTNamespaceAlias) declaration).getAlias(); ASTInternal.addName(scope, alias); } else if (declaration instanceof IASTFunctionDefinition) { IASTFunctionDefinition functionDef = (IASTFunctionDefinition) declaration; final IASTDeclSpecifier declSpec = functionDef.getDeclSpecifier(); IASTFunctionDeclarator declarator = functionDef.getDeclarator(); if (!((ICPPASTDeclSpecifier) declSpec).isFriend()) { // check the function itself IASTName declName = ASTQueries.findInnermostDeclarator(declarator).getName(); ASTInternal.addName(scope, declName); } // Collect elaborated type specifiers and friends final EScopeKind scopeKind = scope.getKind(); switch (scopeKind) { case eLocal: case eGlobal: case eNamespace: NamespaceTypeCollector visitor = new NamespaceTypeCollector(scope); declSpec.accept(visitor); declarator.accept(visitor); break; case eClassType: case eTemplateDeclaration: case eEnumeration: break; } } } /** * Perform lookup in nominated namespaces that appear in the given scope. For unqualified lookups the method assumes * that transitive directives have been stored in the lookup-data. For qualified lookups the transitive directives * are considered if the lookup of the original directive returns empty. * @param fileSet */ private static void lookupInNominated(LookupData data, IIndexFileSet fileSet, ICPPNamespaceScope scope) throws DOMException { List<ICPPNamespaceScope> allNominated= data.usingDirectives.remove(scope); while (allNominated != null) { for (ICPPNamespaceScope nominated : allNominated) { if (data.visited.containsKey(nominated)) { continue; } data.visited.put(nominated); boolean found = false; IBinding[] bindings= getBindingsFromScope(nominated, fileSet, data); if (bindings != null && bindings.length > 0) { mergeResults(data, bindings, true); found = true; } // in the qualified lookup we have to nominate the transitive directives only when // the lookup did not succeed. In the qualified case this is done earlier, when the directive // is encountered. if (!found && data.qualified() && !data.contentAssist) { if (data.tu != null) { data.tu.handleAdditionalDirectives(nominated); } ICPPUsingDirective[] usings= nominated.getUsingDirectives(); for (ICPPUsingDirective using : usings) { storeUsingDirective(data, scope, using, null); } } } // retry with transitive directives that may have been nominated in a qualified lookup allNominated= data.usingDirectives.remove(scope); } } public static IBinding resolveAmbiguities(IASTName name, Object[] bindings) { bindings = ArrayUtil.trim(Object.class, bindings); if (bindings == null || bindings.length == 0) { return null; } else if (bindings.length == 1) { IBinding candidate= null; if (bindings[0] instanceof IBinding) { candidate= (IBinding) bindings[0]; } else if (bindings[0] instanceof IASTName) { candidate= ((IASTName) bindings[0]).getPreBinding(); } else { return null; } if (candidate != null) { if (!(candidate instanceof IType) && !(candidate instanceof ICPPNamespace) && !(candidate instanceof ICPPUsingDeclaration) && LookupData.typesOnly(name)) { return null; } // bug 238180 if (candidate instanceof ICPPClassTemplatePartialSpecialization) return null; // specialization is selected during instantiation if (candidate instanceof ICPPTemplateInstance) candidate= ((ICPPTemplateInstance) candidate).getSpecializedBinding(); if (!(candidate instanceof ICPPFunctionTemplate)) return candidate; } } if (name.getPropertyInParent() != STRING_LOOKUP_PROPERTY) { LookupData data = createLookupData(name); data.foundItems = bindings; try { return resolveAmbiguities(data, name); } catch (DOMException e) { return e.getProblem(); } } IBinding[] result = null; for (Object binding : bindings) { if (binding instanceof IASTName) result = (IBinding[]) ArrayUtil.append(IBinding.class, result, ((IASTName) binding).resolveBinding()); else if (binding instanceof IBinding) result = (IBinding[]) ArrayUtil.append(IBinding.class, result, binding); } return new CPPCompositeBinding(result); } static public boolean declaredBefore(Object obj, IASTNode node, boolean indexBased) { if (node == null) return true; final int pointOfRef= ((ASTNode) node).getOffset(); if (node.getPropertyInParent() == STRING_LOOKUP_PROPERTY && pointOfRef <= 0) { return true; } ASTNode nd = null; if (obj instanceof ICPPSpecialization) { obj = ((ICPPSpecialization) obj).getSpecializedBinding(); } int pointOfDecl= -1; if (obj instanceof ICPPInternalBinding) { ICPPInternalBinding cpp = (ICPPInternalBinding) obj; // for bindings in global or namespace scope we don't know whether there is a // previous declaration in one of the skipped header files. For bindings that // are likely to be redeclared we need to assume that there is a declaration // in one of the headers. if (indexBased && acceptDeclaredAfter(cpp)) { return true; } IASTNode[] n = cpp.getDeclarations(); if (n != null && n.length > 0) { nd = (ASTNode) n[0]; } ASTNode def = (ASTNode) cpp.getDefinition(); if (def != null) { if (nd == null || def.getOffset() < nd.getOffset()) nd = def; } if (nd == null) return true; } else { if (indexBased && obj instanceof IASTName) { IBinding b= ((IASTName) obj).getPreBinding(); if (b instanceof ICPPInternalBinding) { if (acceptDeclaredAfter((ICPPInternalBinding) b)) return true; } } if (obj instanceof ASTNode) { nd = (ASTNode) obj; } else if (obj instanceof ICPPUsingDirective) { pointOfDecl= ((ICPPUsingDirective) obj).getPointOfDeclaration(); } } if (pointOfDecl < 0 && nd != null) { ASTNodeProperty prop = nd.getPropertyInParent(); if (prop == IASTDeclarator.DECLARATOR_NAME || nd instanceof IASTDeclarator) { // point of declaration for a name is immediately after its complete declarator and before its initializer IASTDeclarator dtor = (IASTDeclarator)((nd instanceof IASTDeclarator) ? nd : nd.getParent()); while (dtor.getParent() instanceof IASTDeclarator) dtor = (IASTDeclarator) dtor.getParent(); IASTInitializer init = dtor.getInitializer(); if (init != null) pointOfDecl = ((ASTNode) init).getOffset() - 1; else pointOfDecl = ((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength(); } else if (prop == IASTEnumerator.ENUMERATOR_NAME) { // point of declaration for an enumerator is immediately after it enumerator-definition IASTEnumerator enumtor = (IASTEnumerator) nd.getParent(); if (enumtor.getValue() != null) { ASTNode exp = (ASTNode) enumtor.getValue(); pointOfDecl = exp.getOffset() + exp.getLength(); } else { pointOfDecl = nd.getOffset() + nd.getLength(); } } else if (prop == ICPPASTUsingDeclaration.NAME) { nd = (ASTNode) nd.getParent(); pointOfDecl = nd.getOffset(); } else if (prop == ICPPASTNamespaceAlias.ALIAS_NAME) { nd = (ASTNode) nd.getParent(); pointOfDecl = nd.getOffset() + nd.getLength(); } else { pointOfDecl = nd.getOffset() + nd.getLength(); } } return (pointOfDecl < pointOfRef); } private static boolean acceptDeclaredAfter(ICPPInternalBinding cpp) { try { if (cpp instanceof ICPPNamespace || cpp instanceof ICPPFunction || cpp instanceof ICPPVariable) { IScope scope= cpp.getScope(); if (scope instanceof ICPPBlockScope == false && scope instanceof ICPPNamespaceScope) { return true; } } else if (cpp instanceof ICompositeType || cpp instanceof IEnumeration) { IScope scope= cpp.getScope(); if (scope instanceof ICPPBlockScope == false && scope instanceof ICPPNamespaceScope) { // if this is not the definition, it may be found in a header. (bug 229571) if (cpp.getDefinition() == null) { return true; } } } } catch (DOMException e) { } return false; } private static IBinding resolveAmbiguities(LookupData data, IASTName name) throws DOMException { if (!data.hasResults() || data.contentAssist) return null; final boolean indexBased= data.tu != null && data.tu.getIndex() != null; @SuppressWarnings("unchecked") ObjectSet<ICPPFunction> fns= ObjectSet.EMPTY_SET; IBinding type = null; IBinding obj = null; IBinding temp = null; Object[] items = (Object[]) data.foundItems; for (int i = 0; i < items.length && items[i] != null; i++) { Object o = items[i]; boolean declaredBefore = !data.checkPointOfDecl || declaredBefore(o, name, indexBased); boolean checkResolvedNamesOnly= false; if (!data.checkWholeClassScope && !declaredBefore) { if (name.getRoleOfName(false) != IASTNameOwner.r_reference) { checkResolvedNamesOnly= true; declaredBefore= true; } else { continue; } } if (o instanceof IASTName) { IASTName on= (IASTName) o; if (checkResolvedNamesOnly) { temp = on.getPreBinding(); } else { temp= on.resolvePreBinding(); } if (temp == null) continue; } else if (o instanceof IBinding) { temp = (IBinding) o; } else { continue; } // select among those bindings that have been created without problems. if (temp instanceof IProblemBinding) continue; if (!declaredBefore && !(temp instanceof ICPPMember) && !(temp instanceof IType) && !(temp instanceof IEnumerator)) { continue; } if (temp instanceof ICPPUsingDeclaration) { IBinding[] bindings = ((ICPPUsingDeclaration) temp).getDelegates(); mergeResults(data, bindings, false); items = (Object[]) data.foundItems; continue; } else if (temp instanceof CPPCompositeBinding) { IBinding[] bindings = ((CPPCompositeBinding) temp).getBindings(); mergeResults(data, bindings, false); items = (Object[]) data.foundItems; continue; } else if (temp instanceof ICPPFunction) { if (temp instanceof ICPPTemplateInstance) { temp= ((ICPPTemplateInstance) temp).getSpecializedBinding(); if (!(temp instanceof IFunction)) continue; } if (fns == ObjectSet.EMPTY_SET) fns = new ObjectSet<ICPPFunction>(2); fns.put((ICPPFunction) temp); } else if (temp instanceof IType) { // specializations are selected during instantiation if (temp instanceof ICPPClassTemplatePartialSpecialization) continue; if (temp instanceof ICPPTemplateInstance) { temp= ((ICPPTemplateInstance) temp).getSpecializedBinding(); if (!(temp instanceof IType)) continue; } if (type == null) { type = temp; } else if (!type.equals(temp)) { int c = compareByRelevance(data.tu, type, temp); if (c < 0) { type= temp; } else if (c == 0) { if (((IType) type).isSameType((IType) temp)) { if (type instanceof ITypedef && !(temp instanceof ITypedef)) { // Between same types prefer non-typedef. type= temp; } } else { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } } } } else { if (obj == null) { obj = temp; } else if (obj.equals(temp)) { // Ok, delegates are synonyms. } else { int c = compareByRelevance(data.tu, obj, temp); if (c < 0) { obj= temp; } else if (c == 0) { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } } } } if (data.forUsingDeclaration()) { int cmp= -1; if (obj != null) { cmp= 1; if (fns.size() > 0) { IFunction[] fnArray= fns.keyArray(IFunction.class); cmp= compareByRelevance(data, obj, fnArray); if (cmp == 0) { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } } } IBinding[] bindings = null; if (cmp > 0) { bindings = (IBinding[]) ArrayUtil.append(IBinding.class, bindings, obj); bindings = (IBinding[]) ArrayUtil.append(IBinding.class, bindings, type); } else { bindings = (IBinding[]) ArrayUtil.append(IBinding.class, bindings, type); bindings = (IBinding[]) ArrayUtil.addAll(IBinding.class, bindings, fns.keyArray()); } bindings = (IBinding[]) ArrayUtil.trim(IBinding.class, bindings); ICPPUsingDeclaration composite = new CPPUsingDeclaration(data.astName, bindings); return composite; } if (obj != null && type != null) { if (obj instanceof ICPPNamespace) { if (compareByRelevance(data.tu, type, obj) >= 0) { obj= null; } } else if (!data.typesOnly && overrulesByRelevance(data, type, obj)) { obj= null; } } if (data.typesOnly) { if (obj instanceof ICPPNamespace) return obj; return type; } if (fns.size() > 0) { final ICPPFunction[] fnArray = fns.keyArray(ICPPFunction.class); if (type != null && overrulesByRelevance(data, type, fnArray)) { return type; } if (obj != null) { int cmp= compareByRelevance(data, obj, fnArray); if (cmp == 0) { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } if (cmp > 0) { return obj; } } return resolveFunction(data, fnArray, true); } if (obj != null) { return obj; } return type; } /** * Compares two bindings for relevance in the context of an AST. AST bindings are * considered more relevant than index ones since the index may be out of date, * built for a different configuration, etc. Index bindings reachable through includes * are more relevant than unreachable ones. * @param ast * @param b1 * @param b2 * @return 1 if binding <code>b1</code> is more relevant than <code>b2</code>; 0 if * the two bindings have the same relevance; -1 if <code>b1</code> is less relevant than * <code>b2</code>. */ static int compareByRelevance(IASTTranslationUnit tu, IBinding b1, IBinding b2) { boolean b1FromIndex= isFromIndex(b1); boolean b2FromIndex= isFromIndex(b2); if (b1FromIndex != b2FromIndex) { return !b1FromIndex ? 1 : -1; } else if (b1FromIndex) { // Both are from index. if (tu != null) { boolean b1Reachable= isReachableFromAst(tu, b1); boolean b2Reachable= isReachableFromAst(tu, b2); if (b1Reachable != b2Reachable) { return b1Reachable ? 1 : -1; } } } return 0; } /** * Compares two bindings for relevance in the context of an AST. Type bindings are * considered to overrule object bindings when the former is reachable but the * latter is not. */ static boolean overrulesByRelevance(LookupData data, IBinding type, IBinding b2) { if (data != null && data.tu != null) { return !isReachableFromAst(data.tu, b2) && isReachableFromAst(data.tu, type); } return false; } /** * Compares a binding with a list of function candidates for relevance in the * context of an AST. Types are considered to overrule object bindings when * the former is reachable but none of the functions are. */ static boolean overrulesByRelevance(LookupData data, IBinding type, IFunction[] fns) { if (data == null || data.tu == null) { return false; } for (int i = 0; i < fns.length; i++) { if (!isFromIndex(fns[i])) { return false; // function from ast } } if (!isReachableFromAst(data.tu, type)) { return false; } for (IFunction fn : fns) { if (isReachableFromAst(data.tu, fn)) { return false; // function from ast } } return true; } /** * Compares two bindings for relevance in the context of an AST. AST bindings are * considered more relevant than index ones since the index may be out of date, * built for a different configuration, etc. Index bindings reachable through includes * are more relevant than unreachable ones. * @param ast * @param b1 * @param b2 * @return 1 if binding <code>b1</code> is more relevant than <code>b2</code>; 0 if * the two bindings have the same relevance; -1 if <code>b1</code> is less relevant than * <code>b2</code>. */ static int compareByRelevance(LookupData data, IName b1, IName b2) { boolean b1FromIndex= (b1 instanceof IIndexName); boolean b2FromIndex= (b2 instanceof IIndexName); if (b1FromIndex != b2FromIndex) { return !b1FromIndex ? 1 : -1; } else if (b1FromIndex) { // Both are from index. if (data.tu != null) { boolean b1Reachable= isReachableFromAst(data.tu, b1); boolean b2Reachable= isReachableFromAst(data.tu, b2); if (b1Reachable != b2Reachable) { return b1Reachable ? 1 : -1; } } } return 0; } /** * Compares a binding with a list of function candidates for relevance in the context of an AST. AST bindings are * considered more relevant than index ones since the index may be out of date, * built for a different configuration, etc. Index bindings reachable through includes * are more relevant than unreachable ones. * @return 1 if binding <code>obj</code> is more relevant than the function candidates; 0 if * the they have the same relevance; -1 if <code>obj</code> is less relevant than * the function candidates. */ static int compareByRelevance(LookupData data, IBinding obj, IFunction[] fns) { if (isFromIndex(obj)) { for (int i = 0; i < fns.length; i++) { if (!isFromIndex(fns[i])) { return -1; // function from ast } } // everything is from the index if (!isReachableFromAst(data.tu, obj)) { return -1; // obj not reachable } for (IFunction fn : fns) { if (isReachableFromAst(data.tu, fn)) { return 0; // obj reachable, 1 function reachable } } return 1; // no function is reachable } // obj is not from the index for (int i = 0; i < fns.length; i++) { if (!isFromIndex(fns[i])) { return 0; // obj and function from ast } } return 1; // only obj is from ast. } private static boolean isFromIndex(IBinding binding) { if (binding instanceof IIndexBinding) { return true; } if (binding instanceof ICPPSpecialization) { return ((ICPPSpecialization) binding).getSpecializedBinding() instanceof IIndexBinding; } return false; } /** * Checks if a binding is an AST binding, or is reachable from the AST through includes. * The binding is assumed to belong to the AST, if it is not an IIndexBinding and not * a specialization of an IIndexBinding. * @param ast * @param binding * @return <code>true</code> if the <code>binding</code> is reachable from <code>ast</code>. */ private static boolean isReachableFromAst(IASTTranslationUnit ast, IBinding binding) { IIndexBinding indexBinding = null; if (binding instanceof IIndexBinding) { indexBinding = (IIndexBinding) binding; } if (binding instanceof ICPPSpecialization) { binding = ((ICPPSpecialization) binding).getSpecializedBinding(); if (binding instanceof IIndexBinding) { indexBinding = (IIndexBinding) binding; } } if (indexBinding == null) { // We don't check if the binding really belongs to the AST specified by the ast // parameter assuming that the caller doesn't deal with two ASTs at a time. return true; } IIndexFileSet indexFileSet = ast.getIndexFileSet(); return indexFileSet != null && indexFileSet.containsDeclaration(indexBinding); } /** * Checks if a binding is an AST binding, or is reachable from the AST through includes. * The binding is assumed to belong to the AST, if it is not an IIndexBinding and not * a specialization of an IIndexBinding. * @param ast * @param binding * @return <code>true</code> if the <code>binding</code> is reachable from <code>ast</code>. */ private static boolean isReachableFromAst(IASTTranslationUnit ast, IName name) { if (!(name instanceof IIndexName)) { return true; } IIndexName indexName = (IIndexName) name; try { IIndexFile file= indexName.getFile(); IIndexFileSet indexFileSet = ast.getIndexFileSet(); return indexFileSet != null && indexFileSet.contains(file); } catch (CoreException e) { return false; } } private static ICPPFunction[] selectByArgumentCount(LookupData data, ICPPFunction[] functions) throws DOMException { assert data.forDeclaration() == null; int argumentCount = data.getFunctionArgumentCount(); // Trim the list down to the set of viable functions ICPPFunction[] result= new ICPPFunction[functions.length]; int idx= 0; for (ICPPFunction fn : functions) { if (fn != null && !(fn instanceof IProblemBinding)) { if (fn instanceof ICPPUnknownBinding) { return new ICPPFunction[] {fn}; } // The index is optimized to provide the function type, try not to use the parameters // as long as possible. final ICPPFunctionType ft = fn.getType(); final IType[] parameterTypes = ft.getParameterTypes(); int numPars = parameterTypes.length; if (numPars == 1 && SemanticUtil.isVoidType(parameterTypes[0])) numPars= 0; int numArgs = argumentCount; if (fn instanceof ICPPMethod && data.argsContainImpliedObject) numArgs--; boolean ok; if (numArgs > numPars) { // more arguments than parameters --> need ellipsis or parameter pack ok= fn.takesVarArgs() || fn.hasParameterPack(); } else { ok = numArgs >= fn.getRequiredArgumentCount(); } if (ok) { if (fn instanceof IIndexBinding) { for (ICPPFunction other : result) { if (other == null || other instanceof IIndexBinding) break; if (other.getType().isSameType(ft)) { ok= false; break; } } } if (ok) { result[idx++]= fn; } } } } return result; } public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, boolean allowUDC) throws DOMException { fns= (ICPPFunction[]) ArrayUtil.trim(ICPPFunction.class, fns); if (fns == null || fns.length == 0) return null; sortAstBeforeIndex(fns); if (data.forUsingDeclaration()) return new CPPUsingDeclaration(data.astName, fns); if (data.astName instanceof ICPPASTConversionName) { return resolveUserDefinedConversion(data, fns); } if (data.forDeclaration() != null) { return resolveFunctionDeclaration(data, fns); } // No arguments to resolve function if (!data.hasFunctionArguments()) { return createFunctionSet(data.astName, fns); } // Reduce our set of candidate functions to only those who have the right number of parameters final IType[] argTypes = data.getFunctionArgumentTypes(); ICPPFunction[] tmp= selectByArgumentCount(data, fns); tmp= CPPTemplates.instantiateForFunctionCall(data.astName, tmp, Arrays.asList(argTypes), Arrays.asList(data.getFunctionArgumentValueCategories()), data.argsContainImpliedObject); if (tmp.length == 0 || tmp[0] == null) return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, fns); int viableCount= 0; for (IFunction f : tmp) { if (f instanceof ICPPUnknownBinding) { setTargetedFunctionsToUnknown(argTypes); return f; } if (f == null) break; ++viableCount; } if (viableCount == 0) return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, fns); // Check for dependent arguments fns= tmp; if (CPPTemplates.containsDependentType(argTypes)) { if (viableCount == 1) return fns[0]; setTargetedFunctionsToUnknown(argTypes); return CPPUnknownFunction.createForSample(fns[0]); } IFunction[] ambiguousFunctions= null; // ambiguity, 2 functions are equally good FunctionCost bestFnCost = null; // the cost of the best function // Loop over all functions List<FunctionCost> potentialCosts= null; for (ICPPFunction fn : fns) { if (fn == null) continue; final FunctionCost fnCost= costForFunctionCall(fn, allowUDC, data); if (fnCost == null) continue; if (fnCost == CONTAINS_DEPENDENT_TYPES) { if (viableCount == 1) return fns[0]; setTargetedFunctionsToUnknown(argTypes); return CPPUnknownFunction.createForSample(fns[0]); } if (fnCost.hasDeferredUDC()) { if (potentialCosts == null) { potentialCosts= new ArrayList<FunctionCost>(); } potentialCosts.add(fnCost); continue; } int cmp= fnCost.compareTo(data.tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; } else if (cmp == 0) { ambiguousFunctions= (IFunction[]) ArrayUtil.append(IFunction.class, ambiguousFunctions, fn); } } if (potentialCosts != null) { for (FunctionCost fnCost : potentialCosts) { if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC()) { int cmp= fnCost.compareTo(data.tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; } else if (cmp == 0) { ambiguousFunctions= (IFunction[]) ArrayUtil.append(IFunction.class, ambiguousFunctions, fnCost.getFunction()); } } } } if (bestFnCost == null) return null; if (ambiguousFunctions != null) { ambiguousFunctions= (IFunction[]) ArrayUtil.append(IFunction.class, ambiguousFunctions, bestFnCost.getFunction()); return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, ambiguousFunctions); } if (bestFnCost.hasAmbiguousUserDefinedConversion()) { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } for (int i = 0; i < argTypes.length; i++) { IType iType = argTypes[i]; if (iType instanceof FunctionSetType) { ((FunctionSetType) iType).applySelectedFunction(bestFnCost.getCost(i).getSelectedFunction()); } } IFunction result= bestFnCost.getFunction(); if (bestFnCost.isDirectInitWithCopyCtor()) { Cost c0= bestFnCost.getCost(0); IFunction firstConversion= c0.getUserDefinedConversion(); if (firstConversion instanceof ICPPConstructor) return firstConversion; } return result; } private static IBinding createFunctionSet(IASTName name, ICPPFunction[] fns) { // First try to find a unique function ICPPFunction f= getUniqueFunctionForSet(name, fns); return f == null ? new CPPFunctionSet(fns) : f; } private static ICPPFunction getUniqueFunctionForSet(IASTName name, ICPPFunction[] fns) { // First try to find a unique function if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { name= (IASTName) name.getParent(); } final boolean haveTemplateArgs= name instanceof ICPPASTTemplateId; ICPPFunction result= null; boolean haveASTResult= false; for (ICPPFunction f : fns) { // Use the ast binding final boolean fromIndex = isFromIndex(f); if (haveASTResult && fromIndex) break; if (f instanceof ICPPFunctionTemplate) { // Works only if there are template arguments if (!haveTemplateArgs || result != null) return null; result= f; haveASTResult= !fromIndex; } else if (!haveTemplateArgs) { if (result != null) return null; result= f; haveASTResult= !fromIndex; } } if (result instanceof ICPPFunctionTemplate) return CPPTemplates.instantiateForAddressOfFunction((ICPPFunctionTemplate) result, null, name); return result; } private static void setTargetedFunctionsToUnknown(IType[] argTypes) { for (IType argType : argTypes) { if (argType instanceof FunctionSetType) { ((FunctionSetType) argType).setToUnknown(); } } } /** * Called for declarations with qualified name or template-id. Also for explicit function * specializations or instantiations. */ private static IBinding resolveFunctionDeclaration(LookupData data, ICPPFunction[] fns) throws DOMException { final IASTDeclarator dtor= ASTQueries.findTypeRelevantDeclarator(data.getDeclarator()); final IType t = CPPVisitor.createType(dtor); if (!(t instanceof ICPPFunctionType)) return null; final ICPPFunctionType ft= (ICPPFunctionType) t; IASTName templateID= data.astName; if (templateID.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { templateID= (ICPPASTTemplateId) templateID.getParent(); } // 14.5.4 Friends with template ids require instantiation boolean isFriend= CPPVisitor.isFriendDeclaration(data.forDeclaration()); if (!data.forExplicitFunctionSpecialization() && !(isFriend && templateID instanceof ICPPASTTemplateId)) { // Search for a matching function for (ICPPFunction fn : fns) { if (fn != null && !(fn instanceof IProblemBinding) && !(fn instanceof ICPPUnknownBinding)) { if (isSameFunction(fn, dtor)) { return fn; } } } // 14.5.4 Friends with qualified ids allow for instantiation if (!data.forExplicitFunctionInstantiation() && !(isFriend && templateID.getParent() instanceof ICPPASTQualifiedName)) { return null; } } // Try to instantiate a template IASTTranslationUnit tu= data.tu; ICPPTemplateArgument[] tmplArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS; if (templateID instanceof ICPPASTTemplateId) { tmplArgs = CPPTemplates.createTemplateArgumentArray((ICPPASTTemplateId) templateID); } ICPPFunctionTemplate bestTemplate= null; ICPPFunction bestInst= null; boolean isAmbiguous= false; for (ICPPFunction fn : fns) { if (fn instanceof ICPPFunctionTemplate && !(fn instanceof IProblemBinding) && !(fn instanceof ICPPUnknownBinding)) { ICPPFunctionTemplate template= (ICPPFunctionTemplate) fn; ICPPFunction inst= CPPTemplates.instantiateForFunctionDeclaration(template, tmplArgs, ft); if (inst != null) { int cmp= CPPTemplates.orderFunctionTemplates(bestTemplate, template, TypeSelection.PARAMETERS_AND_RETURN_TYPE); if (cmp == 0) cmp= compareByRelevance(tu, bestTemplate, template); if (cmp == 0) isAmbiguous= true; if (cmp < 0) { isAmbiguous= false; bestTemplate= template; bestInst= inst; } } } } if (isAmbiguous) return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, fns); return bestInst; } public static void sortAstBeforeIndex(IFunction[] fns) { int iast= 0; for (int i = 0; i < fns.length; i++) { IFunction fn= fns[i]; if (!(fn instanceof IIndexBinding)) { if (iast != i) { fns[i]= fns[iast]; fns[iast]= fn; } iast++; } } } private static FunctionCost costForFunctionCall(ICPPFunction fn, boolean allowUDC, LookupData data) throws DOMException { IType[] argTypes = data.getFunctionArgumentTypes(); ValueCategory[] isLValue= data.getFunctionArgumentValueCategories(); int skipArg= 0; final ICPPFunctionType ftype= fn.getType(); if (ftype == null) return null; IType implicitParameterType= null; IType impliedObjectType= null; final IType[] paramTypes= ftype.getParameterTypes(); if (fn instanceof ICPPMethod && !(fn instanceof ICPPConstructor)) { implicitParameterType = getImplicitParameterType((ICPPMethod) fn); if (data.argsContainImpliedObject) { impliedObjectType= argTypes[0]; skipArg= 1; } } int k= 0; Cost cost; final int sourceLen= argTypes.length - skipArg; final FunctionCost result; if (implicitParameterType == null) { result= new FunctionCost(fn, sourceLen); } else { result= new FunctionCost(fn, sourceLen + 1); ValueCategory sourceIsLValue= LVALUE; if (impliedObjectType == null) { impliedObjectType= data.getImpliedObjectType(); } if (fn instanceof ICPPMethod && (((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) { // 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY); cost.setImpliedObject(); } else if (impliedObjectType == null) { return null; } else if (impliedObjectType.isSameType(implicitParameterType)) { cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY); cost.setImpliedObject(); } else { cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.FORBIDDEN, Context.IMPLICIT_OBJECT); if (cost.converts()) { cost.setImpliedObject(); } else { if (CPPTemplates.isDependentType(implicitParameterType) || CPPTemplates.isDependentType(impliedObjectType)) { IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE); IType t= getNestedType(implicitParameterType, TDEF|REF|CVTYPE); if (SemanticUtil.calculateInheritanceDepth(s, t) >= 0) return null; return CONTAINS_DEPENDENT_TYPES; } } } if (!cost.converts()) return null; result.setCost(k++, cost, sourceIsLValue); } final UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN; for (int j = 0; j < sourceLen; j++) { final IType argType= SemanticUtil.getNestedType(argTypes[j+skipArg], TDEF | REF); if (argType == null) return null; final ValueCategory sourceIsLValue = isLValue[j+skipArg]; IType paramType; if (j < paramTypes.length) { paramType= getNestedType(paramTypes[j], TDEF); } else if (!fn.takesVarArgs()) { paramType= VOID_TYPE; } else { cost = new Cost(argType, null, Rank.ELLIPSIS_CONVERSION); result.setCost(k++, cost, sourceIsLValue); continue; } if (argType instanceof FunctionSetType) { cost= ((FunctionSetType) argType).costForTarget(paramType); } else if (argType.isSameType(paramType)) { cost = new Cost(argType, paramType, Rank.IDENTITY); } else { if (CPPTemplates.isDependentType(paramType)) return CONTAINS_DEPENDENT_TYPES; Context ctx= Context.ORDINARY; if (j == 0 && sourceLen == 1 && fn instanceof ICPPConstructor) { if (paramType instanceof ICPPReferenceType) { if (((ICPPConstructor) fn).getClassOwner().isSameType(getNestedType(paramType, TDEF|REF|CVTYPE))) { ctx= Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR; result.setIsDirectInitWithCopyCtor(true); } } } cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, ctx); if (data.fNoNarrowing && cost.isNarrowingConversion()) { cost= Cost.NO_CONVERSION; } } if (!cost.converts()) return null; result.setCost(k++, cost, sourceIsLValue); } return result; } static IType getImplicitParameterType(ICPPMethod m) throws DOMException { IType implicitType; ICPPClassType owner= m.getClassOwner(); if (owner instanceof ICPPClassTemplate) { owner= CPPTemplates.instantiateWithinClassTemplate((ICPPClassTemplate) owner); } ICPPFunctionType ft= m.getType(); implicitType= SemanticUtil.addQualifiers(owner, ft.isConst(), ft.isVolatile(), false); return new CPPReferenceType(implicitType, false); } private static IBinding resolveUserDefinedConversion(LookupData data, ICPPFunction[] fns) { ICPPASTConversionName astName= (ICPPASTConversionName) data.astName; IType t= CPPVisitor.createType(astName.getTypeId()); if (t instanceof ISemanticProblem) { return new ProblemBinding(astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } if (data.forDeclaration() == null || data.forExplicitFunctionSpecialization() || data.forExplicitFunctionInstantiation()) { fns= CPPTemplates.instantiateConversionTemplates(fns, t); } IFunction unknown= null; for (IFunction function : fns) { if (function != null) { IType t2= function.getType().getReturnType(); if (t.isSameType(t2)) return function; if (unknown == null && function instanceof ICPPUnknownBinding) { unknown= function; } } } if (unknown != null) return unknown; return new ProblemBinding(astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, data.getFoundBindings()); } /** * 13.4-1 A use of an overloaded function without arguments is resolved in certain contexts to a function */ static IBinding resolveTargetedFunction(IASTName name, ICPPFunction[] fns) { boolean addressOf= false; IASTNode node= name.getParent(); while (node instanceof IASTName) node= node.getParent(); if (!(node instanceof IASTIdExpression)) return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD); ASTNodeProperty prop= node.getPropertyInParent(); IASTNode parent = node.getParent(); while (parent instanceof IASTUnaryExpression) { final int op= ((IASTUnaryExpression) parent).getOperator(); if (op == IASTUnaryExpression.op_bracketedPrimary) { } else if (!addressOf && op == IASTUnaryExpression.op_amper) { addressOf= true; } else { break; } node= parent; prop= node.getPropertyInParent(); parent= node.getParent(); } IType targetType= null; if (prop == IASTDeclarator.INITIALIZER) { // Target is an object or reference being initialized IASTDeclarator dtor = (IASTDeclarator) parent; targetType= CPPVisitor.createType(dtor); } else if (prop == IASTEqualsInitializer.INITIALIZER) { final IASTNode grandpa = parent.getParent(); if (grandpa instanceof IASTDeclarator) { IASTDeclarator dtor = ASTQueries.findInnermostDeclarator((IASTDeclarator) grandpa); IBinding var= dtor.getName().resolvePreBinding(); if (var instanceof IVariable) targetType= ((IVariable) var).getType(); } } else if (prop == ICPPASTConstructorInitializer.ARGUMENT) { ICPPASTConstructorInitializer init = (ICPPASTConstructorInitializer) parent; final IASTNode parentOfInit = init.getParent(); if (parentOfInit instanceof IASTDeclarator) { IASTDeclarator dtor = (IASTDeclarator) parentOfInit; targetType= CPPVisitor.createType(dtor); } else if (parentOfInit instanceof ICPPASTConstructorChainInitializer) { ICPPASTConstructorChainInitializer memInit= (ICPPASTConstructorChainInitializer) parentOfInit; IBinding var= memInit.getMemberInitializerId().resolveBinding(); if (var instanceof IVariable) { targetType= ((IVariable) var).getType(); } } targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR); if (init.getArguments().length != 1 || !(targetType instanceof ICPPFunctionType)) { if (targetType instanceof ICPPClassType) { LookupData data= new LookupData(name); data.setFunctionArguments(false, init.getArguments()); try { IBinding ctor = CPPSemantics.resolveFunction(data, ((ICPPClassType) targetType).getConstructors(), true); if (ctor instanceof ICPPConstructor) { int i= 0; for (IASTNode arg : init.getArguments()) { if (arg == node) { IType[] params= ((ICPPConstructor) ctor).getType().getParameterTypes(); if (params.length > i) { targetType= params[i]; } break; } i++; } } } catch (DOMException e) { } } } } else if (prop == IASTBinaryExpression.OPERAND_TWO) { IASTBinaryExpression binaryExp = (IASTBinaryExpression) parent; if (binaryExp.getOperator() == IASTBinaryExpression.op_assign) { targetType= binaryExp.getOperand1().getExpressionType(); } } else if (prop == IASTFunctionCallExpression.ARGUMENT) { // Target is a parameter of a function, need to resolve the function call IASTFunctionCallExpression fnCall = (IASTFunctionCallExpression) parent; IType t= SemanticUtil.getNestedType(fnCall.getFunctionNameExpression().getExpressionType(), TDEF|REF|CVTYPE); if (t instanceof IPointerType) { t= SemanticUtil.getNestedType(((IPointerType) t).getType(), TDEF | REF | CVTYPE); } if (t instanceof IFunctionType) { int i= 0; for (IASTNode arg : fnCall.getArguments()) { if (arg == node) { IType[] params= ((IFunctionType) t).getParameterTypes(); if (params.length > i) { targetType= params[i]; } break; } i++; } } } else if (prop == IASTCastExpression.OPERAND) { // target is an explicit type conversion IASTCastExpression cast = (IASTCastExpression) parent; targetType= CPPVisitor.createType(cast.getTypeId().getAbstractDeclarator()); } else if (prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) { // target is a template non-type parameter (14.3.2-5) ICPPASTTemplateId id = (ICPPASTTemplateId) parent; IASTNode[] args = id.getTemplateArguments(); int i = 0; for (; i < args.length; i++) { if (args[i] == node) { break; } } IBinding template = id.getTemplateName().resolveBinding(); if (template instanceof ICPPTemplateDefinition) { ICPPTemplateParameter[] ps = ((ICPPTemplateDefinition) template).getTemplateParameters(); if (i < args.length && i < ps.length && ps[i] instanceof ICPPTemplateNonTypeParameter) { targetType= ((ICPPTemplateNonTypeParameter) ps[i]).getType(); } } } else if (prop == IASTReturnStatement.RETURNVALUE) { // target is the return value of a function, operator or conversion while (parent != null && !(parent instanceof IASTFunctionDefinition)) { parent = parent.getParent(); } if (parent instanceof IASTFunctionDefinition) { IASTDeclarator dtor = ((IASTFunctionDefinition) parent).getDeclarator(); dtor= ASTQueries.findInnermostDeclarator(dtor); IBinding binding = dtor.getName().resolveBinding(); if (binding instanceof IFunction) { IFunctionType ft = ((IFunction) binding).getType(); targetType= ft.getReturnType(); } } } if (targetType == null && parent instanceof IASTExpression && parent instanceof IASTImplicitNameOwner) { // Trigger resolution of overloaded operator, which may resolve the // function set. ((IASTImplicitNameOwner) parent).getImplicitNames(); final IBinding newBinding = name.getPreBinding(); if (!(newBinding instanceof CPPFunctionSet)) return newBinding; } ICPPFunction function = resolveTargetedFunction(targetType, name, fns); if (function == null) return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD); return function; } static ICPPFunction resolveTargetedFunction(IType targetType, IASTName name, ICPPFunction[] fns) { targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR); if (!(targetType instanceof ICPPFunctionType)) return null; // First pass, consider functions for (ICPPFunction fn : fns) { if (!(fn instanceof ICPPFunctionTemplate)) { if (targetType.isSameType(fn.getType())) return fn; } } // Second pass, consider templates ICPPFunction result= null; ICPPFunctionTemplate resultTemplate= null; boolean isAmbiguous= false; final IASTTranslationUnit tu= name.getTranslationUnit(); for (IFunction fn : fns) { try { if (fn instanceof ICPPFunctionTemplate) { final ICPPFunctionTemplate template = (ICPPFunctionTemplate) fn; ICPPFunction inst= CPPTemplates.instantiateForAddressOfFunction(template, (ICPPFunctionType) targetType, name); if (inst != null) { int cmp= CPPTemplates.orderFunctionTemplates(resultTemplate, template, TypeSelection.PARAMETERS_AND_RETURN_TYPE); if (cmp == 0) cmp= compareByRelevance(tu, resultTemplate, template); if (cmp == 0) isAmbiguous= true; if (cmp < 0) { isAmbiguous= false; resultTemplate= template; result= inst; } } } } catch (DOMException e) { } } if (isAmbiguous) return null; return result; } public static ICPPFunction findOverloadedOperator(IASTArraySubscriptExpression exp) { final IASTExpression arrayExpression = exp.getArrayExpression(); IASTInitializerClause[] args = {arrayExpression, exp.getArgument()}; IType type = typeOrFunctionSet(arrayExpression); type = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); return findOverloadedOperator(exp, args, type, OverloadableOperator.BRACKET, LookupMode.NO_GLOBALS); } public static ICPPFunction findOverloadedOperator(IASTFunctionCallExpression exp, ICPPClassType type) { IASTInitializerClause[] args = exp.getArguments(); ArrayList<IASTInitializerClause> argsToPass = new ArrayList<IASTInitializerClause>(args.length + 1); argsToPass.add(exp.getFunctionNameExpression()); for (IASTInitializerClause e : args) { argsToPass.add(e); } args = argsToPass.toArray(new IASTInitializerClause[argsToPass.size()]); return findOverloadedOperator(exp, args, type, OverloadableOperator.PAREN, LookupMode.NO_GLOBALS); } public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression expr) { OverloadableOperator op = OverloadableOperator.fromNewExpression(expr); IType type = getTypeOfPointer(expr.getExpressionType()); if (type == null) return null; IASTTypeId typeId = expr.getTypeId().copy(); IASTExpression sizeExpression = new CPPASTTypeIdExpression(IASTTypeIdExpression.op_sizeof, typeId); sizeExpression.setParent(expr); IASTInitializerClause[] placement = expr.getPlacementArguments(); List<IASTInitializerClause> args = new ArrayList<IASTInitializerClause>(); args.add(createArgForType(expr, type)); args.add(sizeExpression); if (placement != null) { for (IASTInitializerClause p : placement) { args.add(p); } } IASTInitializerClause[] argArray = args.toArray(new IASTInitializerClause[args.size()]); return findOverloadedOperator(expr, argArray, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); } public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression expr) { OverloadableOperator op = OverloadableOperator.fromDeleteExpression(expr); IType type = getTypeOfPointer(expr.getOperand().getExpressionType()); if (type == null) return null; IASTExpression[] args = {createArgForType(expr, type), expr.getOperand()}; return findOverloadedOperator(expr, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); } private static IType getTypeOfPointer(IType type) { type = SemanticUtil.getNestedType(type, SemanticUtil.TDEF | SemanticUtil.REF | SemanticUtil.CVTYPE); if (type instanceof IPointerType) { return getNestedType(((IPointerType) type).getType(), TDEF | REF | CVTYPE); } return null; } /** * Returns constructor called by a declarator, or <code>null</code> if no constructor is called. */ public static ICPPConstructor findImplicitlyCalledConstructor(final ICPPASTDeclarator declarator) { if (declarator.getNestedDeclarator() != null) return null; IASTDeclarator dtor= ASTQueries.findOutermostDeclarator(declarator); IASTNode parent = dtor.getParent(); if (parent instanceof IASTSimpleDeclaration) { final IASTInitializer initializer = dtor.getInitializer(); if (initializer == null) { IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); parent = parent.getParent(); if (parent instanceof IASTCompositeTypeSpecifier || declSpec.getStorageClass() == IASTDeclSpecifier.sc_extern) { // No initialization is performed for class members and extern declarations // without an initializer. return null; } } return findImplicitlyCalledConstructor(declarator.getName(), initializer); } return null; } /** * Returns constructor called by a class member initializer in a constructor initializer chain. * Returns <code>null</code> if no constructor is called. */ public static ICPPConstructor findImplicitlyCalledConstructor(ICPPASTConstructorChainInitializer initializer) { return findImplicitlyCalledConstructor(initializer.getMemberInitializerId(), initializer.getInitializer()); } /** * Returns constructor called by a variable declarator or an initializer in a constructor initializer * chain. Returns <code>null</code> if no constructor is called. */ private static ICPPConstructor findImplicitlyCalledConstructor(IASTName name, IASTInitializer initializer) { IBinding binding = name.resolveBinding(); if (!(binding instanceof ICPPVariable)) return null; IType type; try { type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE); if (!(type instanceof ICPPClassType)) return null; if (type instanceof ICPPClassTemplate || type instanceof ICPPUnknownClassType || type instanceof ISemanticProblem) return null; final ICPPClassType classType = (ICPPClassType) type; if (initializer instanceof IASTEqualsInitializer) { // Copy initialization IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer; IASTInitializerClause initClause = eqInit.getInitializerClause(); IType sourceType= null; ValueCategory isLValue= PRVALUE; if (initClause instanceof IASTExpression) { final IASTExpression expr = (IASTExpression) initClause; isLValue= valueCat(expr); sourceType= SemanticUtil.getSimplifiedType(typeOrFunctionSet(expr)); } else if (initClause instanceof ICPPASTInitializerList) { sourceType= new InitializerListType((ICPPASTInitializerList) initClause); } if (sourceType != null) { Cost c; if (calculateInheritanceDepth(sourceType, classType) >= 0) { c = Conversions.copyInitializationOfClass(isLValue, sourceType, classType, false); } else { c = Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED, Context.ORDINARY); } if (c.converts()) { ICPPFunction f = c.getUserDefinedConversion(); if (f instanceof ICPPConstructor) return (ICPPConstructor) f; // If a conversion is used, the constructor is elided. } } } else if (initializer instanceof ICPPASTInitializerList) { // List initialization final InitializerListType listType = new InitializerListType((ICPPASTInitializerList) initializer); Cost c= Conversions.listInitializationSequence(listType, type, UDCMode.ALLOWED, true); if (c.converts()) { ICPPFunction f = c.getUserDefinedConversion(); if (f instanceof ICPPConstructor) return (ICPPConstructor) f; } } else if (initializer instanceof ICPPASTConstructorInitializer) { // Direct Initialization final IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initializer).getArguments(); CPPASTName astName = new CPPASTName(); astName.setName(classType.getNameCharArray()); astName.setOffsetAndLength((ASTNode) name); CPPASTIdExpression idExp = new CPPASTIdExpression(astName); idExp.setParent(name.getParent()); idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); LookupData data = new LookupData(astName); data.setFunctionArguments(false, arguments); data.forceQualified = true; data.foundItems = classType.getConstructors(); binding = resolveAmbiguities(data, astName); if (binding instanceof ICPPConstructor) return (ICPPConstructor) binding; } else if (initializer == null) { // Default initialization ICPPConstructor[] ctors = classType.getConstructors(); for (ICPPConstructor ctor : ctors) { if (ctor.getRequiredArgumentCount() == 0) return ctor; } return null; } } catch (DOMException e) { } return null; } public static ICPPFunction findImplicitlyCalledDestructor(ICPPASTDeleteExpression expr) { IType t = getTypeOfPointer(expr.getOperand().getExpressionType()); if (!(t instanceof ICPPClassType)) return null; ICPPClassType cls = (ICPPClassType) t; IScope scope = cls.getCompositeScope(); if (scope == null) return null; CPPASTName astName = new CPPASTName(); astName.setParent(expr); astName.setPropertyInParent(STRING_LOOKUP_PROPERTY); astName.setName(CharArrayUtils.concat("~".toCharArray(), cls.getNameCharArray())); //$NON-NLS-1$ IASTExpression arg = createArgForType(expr, cls); LookupData data = new LookupData(astName); data.forceQualified = true; data.setFunctionArguments(true, arg); try { lookup(data, scope); IBinding binding = resolveAmbiguities(data, astName); if (binding instanceof ICPPFunction) return (ICPPFunction) binding; } catch (DOMException e) { } return null; } public static IASTExpression createArgForType(IASTNode node, final IType type) { CPPASTName x= new CPPASTName(); x.setBinding(new CPPVariable(x) { @Override public IType getType() { return type; } }); final CPPASTIdExpression idExpression = new CPPASTIdExpression(x); idExpression.setParent(node); return idExpression; } public static ICPPFunction findOverloadedOperator(IASTUnaryExpression exp) { final IASTExpression operand = exp.getOperand(); if (operand == null) return null; OverloadableOperator op = OverloadableOperator.fromUnaryExpression(exp); if (op == null) return null; IType type = typeOrFunctionSet(operand); type = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); if (!isUserDefined(type)) return null; IASTExpression[] args; int operator = exp.getOperator(); if (operator == IASTUnaryExpression.op_postFixDecr || operator == IASTUnaryExpression.op_postFixIncr) { args = new IASTExpression[] { operand, CPPASTLiteralExpression.INT_ZERO }; } else { args = new IASTExpression[] { operand }; } return findOverloadedOperator(exp, args, type, op, LookupMode.LIMITED_GLOBALS); } public static ICPPFunction findOverloadedOperator(IASTBinaryExpression exp) { OverloadableOperator op = OverloadableOperator.fromBinaryExpression(exp); if (op == null) return null; final IASTExpression op1 = exp.getOperand1(); final IASTExpression op2 = exp.getOperand2(); if(op2==null){ return null; } IType op1type = getNestedType(typeOrFunctionSet(op1), TDEF | REF | CVTYPE); IType op2type = getNestedType(typeOrFunctionSet(op2), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined(op2type)) return null; final IASTExpression[] args = new IASTExpression[] { op1, op2 }; final LookupMode lookupNonMember; if (exp.getOperator() == IASTBinaryExpression.op_assign) { lookupNonMember = LookupMode.NO_GLOBALS; } else { lookupNonMember= LookupMode.LIMITED_GLOBALS; } return findOverloadedOperator(exp, args, op1type, op, lookupNonMember); } /** * For simplicity returns an operator of form RT (T, T) rather than RT (boolean, T, T) */ public static ICPPFunction findOverloadedConditionalOperator(IASTExpression positive, IASTExpression negative) { final IASTExpression parent = (IASTExpression) positive.getParent(); final IASTExpression[] args = new IASTExpression[] {positive, negative}; return findOverloadedOperator(parent, args, null, OverloadableOperator.CONDITIONAL_OPERATOR, LookupMode.NO_GLOBALS); } /** * Returns the operator,() function that would apply to the two given arguments. * The lookup type of the class where the operator,() might be found must also be provided. */ public static ICPPFunction findOverloadedOperatorComma(IASTExpression first, final IType lookupType, final ValueCategory valueCat, IASTExpression second) { IType op1type = getNestedType(lookupType, TDEF | REF | CVTYPE); IType op2type = getNestedType(typeOrFunctionSet(second), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined(op2type)) return null; IASTUnaryExpression dummy = new CPPASTUnaryExpression() { @Override public IType getExpressionType() { return lookupType; } @Override public ValueCategory getValueCategory() { return valueCat; } }; dummy.setParent(first); IASTExpression[] args = new IASTExpression[] { dummy , second }; return findOverloadedOperator(dummy, args, op1type, OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS); } /** * Returns the operator->() function */ public static ICPPFunction findOverloadedOperator(ICPPASTFieldReference fieldRef, IType cvQualifiedType, ICPPClassType classType) { IASTExpression arg = CPPSemantics.createArgForType(fieldRef, cvQualifiedType); return findOverloadedOperator(fieldRef, new IASTExpression[] {arg}, classType, OverloadableOperator.ARROW, LookupMode.NO_GLOBALS); } private static enum LookupMode {NO_GLOBALS, GLOBALS_IF_NO_MEMBERS, LIMITED_GLOBALS, ALL_GLOBALS} private static ICPPFunction findOverloadedOperator(IASTExpression parent, IASTInitializerClause[] args, IType methodLookupType, OverloadableOperator operator, LookupMode mode) { ICPPClassType callToObjectOfClassType= null; IType type2= null; if (args.length >= 2 && args[1] instanceof IASTExpression) { type2 = typeOrFunctionSet((IASTExpression) args[1]); type2= getNestedType(type2, TDEF | REF | CVTYPE); } if (methodLookupType instanceof ICPPUnknownType || type2 instanceof ICPPUnknownType) { if (methodLookupType instanceof FunctionSetType) ((FunctionSetType) methodLookupType).setToUnknown(); if (type2 instanceof FunctionSetType) ((FunctionSetType) type2).setToUnknown(); return new CPPUnknownFunction(null, operator.toCharArray()); } // Find a method LookupData methodData = null; CPPASTName methodName = null; if (methodLookupType instanceof ISemanticProblem) return null; if (methodLookupType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) methodLookupType; methodName = new CPPASTName(operator.toCharArray()); methodName.setParent(parent); methodName.setPropertyInParent(STRING_LOOKUP_PROPERTY); methodData = new LookupData(methodName); methodData.setFunctionArguments(true, args); methodData.forceQualified = true; // (13.3.1.2.3) try { IScope scope = classType.getCompositeScope(); if (scope == null) return null; lookup(methodData, scope); if (parent instanceof IASTFunctionCallExpression) { callToObjectOfClassType= classType; } } catch (DOMException e) { return null; } } // Find a function CPPASTName funcName = new CPPASTName(operator.toCharArray()); funcName.setParent(parent); funcName.setPropertyInParent(STRING_LOOKUP_PROPERTY); LookupData funcData = new LookupData(funcName); // Global new and delete operators do not take an argument for the this pointer. switch (operator) { case DELETE: case DELETE_ARRAY: case NEW: case NEW_ARRAY: args= ArrayUtil.removeFirst(args); break; default: break; } funcData.setFunctionArguments(true, args); funcData.ignoreMembers = true; // (13.3.1.2.3) boolean haveMembers= methodData != null && methodData.hasResults(); if (mode == LookupMode.ALL_GLOBALS || mode == LookupMode.LIMITED_GLOBALS || (mode == LookupMode.GLOBALS_IF_NO_MEMBERS && !haveMembers)) { try { IScope scope = CPPVisitor.getContainingScope(parent); if (scope == null) return null; lookup(funcData, scope); try { doKoenigLookup(funcData); } catch (DOMException e) { } // Filter with file-set IASTTranslationUnit tu= parent.getTranslationUnit(); if (tu != null && funcData.foundItems instanceof Object[]) { final IIndexFileSet fileSet = tu.getIndexFileSet(); if (fileSet != null) { int j=0; final Object[] items= (Object[]) funcData.foundItems; for (int i = 0; i < items.length; i++) { Object item = items[i]; items[i]= null; if (item instanceof IIndexBinding) { if (!fileSet.containsDeclaration((IIndexBinding) item)) { continue; } } items[j++]= item; } } } } catch (DOMException e) { return null; } if (operator == OverloadableOperator.NEW || operator == OverloadableOperator.DELETE || operator == OverloadableOperator.NEW_ARRAY || operator == OverloadableOperator.DELETE_ARRAY) { // Those operators replace the built-in operator Object[] items= (Object[]) funcData.foundItems; int j= 0; for (Object object : items) { if (object instanceof ICPPFunction) { ICPPFunction func= (ICPPFunction) object; if (!(func instanceof CPPImplicitFunction)) items[j++]= func; } } if (j>0) { while (j < items.length) items[j++]= null; } } // 13.3.1.2.3 // However, if no operand type has class type, only those non-member functions ... if (mode == LookupMode.LIMITED_GLOBALS) { if (funcData.foundItems != null && !(methodLookupType instanceof ICPPClassType) && !(type2 instanceof ICPPClassType)) { IEnumeration enum1= null; IEnumeration enum2= null; if (methodLookupType instanceof IEnumeration) { enum1= (IEnumeration) methodLookupType; } if (type2 instanceof IEnumeration) { enum2= (IEnumeration) type2; } Object[] items= (Object[]) funcData.foundItems; int j= 0; for (Object object : items) { if (object instanceof ICPPFunction) { ICPPFunction func= (ICPPFunction) object; ICPPFunctionType ft = func.getType(); IType[] pts= ft.getParameterTypes(); if ((enum1 != null && pts.length > 0 && enum1.isSameType(getUltimateTypeUptoPointers(pts[0]))) || (enum2 != null && pts.length > 1 && enum2.isSameType(getUltimateTypeUptoPointers(pts[1])))) { items[j++]= object; } } } while (j < items.length) { items[j++]= null; } } } } if (callToObjectOfClassType != null) { try { // 13.3.1.1.2 call to object of class type ICPPMethod[] ops = SemanticUtil.getConversionOperators(callToObjectOfClassType); for (ICPPMethod op : ops) { if (op.isExplicit()) continue; IFunctionType ft= op.getType(); if (ft != null) { IType rt= SemanticUtil.getNestedType(ft.getReturnType(), SemanticUtil.TDEF); if (rt instanceof IPointerType) { IType ptt= SemanticUtil.getNestedType(((IPointerType) rt).getType(), SemanticUtil.TDEF); if (ptt instanceof IFunctionType) { IFunctionType ft2= (IFunctionType) ptt; IBinding sf= createSurrogateCallFunction(parent.getTranslationUnit().getScope(), ft2.getReturnType(), rt, ft2.getParameterTypes()); mergeResults(funcData, sf, false); } } } } } catch (DOMException e) { return null; } } if (methodLookupType instanceof ICPPClassType || type2 instanceof ICPPClassType) { ICPPFunction[] builtins= BuiltinOperators.create(operator, args, parent.getTranslationUnit(), (Object[]) funcData.foundItems); mergeResults(funcData, builtins, false); } try { IBinding binding = null; if (methodData != null && funcData.hasResults()) { // if there was two lookups then merge the results mergeResults(funcData, methodData.foundItems, false); binding = resolveAmbiguities(funcData, funcName); } else if (funcData.hasResults()) { binding = resolveAmbiguities(funcData, funcName); } else if (methodData != null) { binding = resolveAmbiguities(methodData, methodName); } if (binding instanceof ICPPFunction) return (ICPPFunction) binding; } catch (DOMException e) { } return null; } private static IBinding createSurrogateCallFunction(IScope scope, IType returnType, IType rt, IType[] parameterTypes) { IType[] parms = new IType[parameterTypes.length + 1]; ICPPParameter[] theParms = new ICPPParameter[parms.length]; parms[0] = rt; theParms[0]= new CPPBuiltinParameter(rt); for (int i = 1; i < parms.length; i++) { IType t = parameterTypes[i - 1]; parms[i]= t; theParms[i]= new CPPBuiltinParameter(t); } ICPPFunctionType functionType = new CPPFunctionType(returnType, parms); return new CPPImplicitFunction(CALL_FUNCTION, scope, functionType, theParms, false); } private static boolean isUserDefined(IType type) { if (type instanceof ISemanticProblem) return false; return type instanceof ICPPClassType || type instanceof IEnumeration || type instanceof ICPPUnknownType; } public static IBinding[] findBindings(IScope scope, String name, boolean qualified) { return findBindings(scope, name.toCharArray(), qualified, null); } public static IBinding[] findBindings(IScope scope, char[] name, boolean qualified) { return findBindings(scope, name, qualified, null); } public static IBinding[] findBindings(IScope scope, char[] name, boolean qualified, IASTNode beforeNode) { CPPASTName astName = new CPPASTName(); astName.setName(name); astName.setParent(ASTInternal.getPhysicalNodeOfScope(scope)); astName.setPropertyInParent(STRING_LOOKUP_PROPERTY); if (beforeNode instanceof ASTNode) { astName.setOffsetAndLength((ASTNode) beforeNode); } LookupData data = new LookupData(astName); data.forceQualified = qualified; return standardLookup(data, scope); } public static IBinding[] findBindingsForContentAssist(IASTName name, boolean prefixLookup, String[] additionalNamespaces) { LookupData data = createLookupData(name); data.contentAssist = true; data.prefixLookup = prefixLookup; data.foundItems = new CharArrayObjectMap(2); // Convert namespaces to scopes. List<ICPPScope> nsScopes= new ArrayList<ICPPScope>(); IASTTranslationUnit tu = name.getTranslationUnit(); if (additionalNamespaces != null && tu != null) { for (String nsName : additionalNamespaces) { nsName= nsName.trim(); if (nsName.startsWith("::")) { //$NON-NLS-1$ nsName= nsName.substring(2); } String[] namespaceParts = nsName.split("::"); //$NON-NLS-1$ try { ICPPScope nsScope = getNamespaceScope(tu, namespaceParts); if (nsScope != null) { nsScopes.add(nsScope); } } catch (DOMException e) { // Errors in source code, continue with next candidate. } } } return contentAssistLookup(data, nsScopes); } private static ICPPScope getNamespaceScope(IASTTranslationUnit tu, String[] namespaceParts) throws DOMException { ICPPScope nsScope= (ICPPScope) tu.getScope(); outer: for (String nsPart : namespaceParts) { nsPart= nsPart.trim(); if (nsPart.length() != 0) { CPPASTName searchName= new CPPASTName(nsPart.toCharArray()); searchName.setParent(tu); searchName.setPropertyInParent(STRING_LOOKUP_PROPERTY); IBinding[] nsBindings = nsScope.getBindings(searchName, true, false); for (IBinding nsBinding : nsBindings) { if (nsBinding instanceof ICPPNamespace) { nsScope= ((ICPPNamespace) nsBinding).getNamespaceScope(); continue outer; } } // There was no matching namespace return null; } } // Name did not specify a namespace, e.g. "::" if (nsScope == tu.getScope()) return null; return nsScope; } private static IBinding[] contentAssistLookup(LookupData data, List<ICPPScope> additionalNamespaces) { try { lookup(data, null); if (additionalNamespaces != null) { data.ignoreUsingDirectives = true; data.forceQualified = true; for (ICPPScope nsScope : additionalNamespaces) { if (!data.visited.containsKey(nsScope)) { lookup(data, nsScope); } } } } catch (DOMException e) { } CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; IBinding[] result = IBinding.EMPTY_BINDING_ARRAY; if (!map.isEmpty()) { char[] key = null; int size = map.size(); for (int i = 0; i < size; i++) { key = map.keyAt(i); result = addContentAssistBinding(result, map.get(key)); } } return ArrayUtil.trim(result); } public static IBinding[] addContentAssistBinding(IBinding[] result, Object obj) { if (obj instanceof Object[]) { for (Object o : (Object[]) obj) { result= addContentAssistBinding(result, o); } return result; } if (obj instanceof IASTName) { return addContentAssistBinding(result, ((IASTName) obj).resolveBinding()); } if (obj instanceof IBinding && !(obj instanceof IProblemBinding)) { final IBinding binding = (IBinding) obj; if (binding instanceof ICPPFunction) { final ICPPFunction function = (ICPPFunction) binding; if (function.isDeleted()) { return result; } } return ArrayUtil.append(result, binding); } return result; } private static IBinding[] standardLookup(LookupData data, IScope start) { try { lookup(data, start); } catch (DOMException e) { return new IBinding[] { e.getProblem() }; } Object[] items = (Object[]) data.foundItems; if (items == null) return new IBinding[0]; ObjectSet<IBinding> set = new ObjectSet<IBinding>(items.length); IBinding binding = null; for (Object item : items) { if (item instanceof IASTName) { binding = ((IASTName) item).resolveBinding(); } else if (item instanceof IBinding) { binding = (IBinding) item; } else { binding = null; } if (binding != null) { if (binding instanceof ICPPUsingDeclaration) { set.addAll(((ICPPUsingDeclaration) binding).getDelegates()); } else if (binding instanceof CPPCompositeBinding) { set.addAll(((CPPCompositeBinding) binding).getBindings()); } else { set.put(binding); } } } return set.keyArray(IBinding.class); } public static boolean isSameFunction(ICPPFunction function, IASTDeclarator declarator) { final ICPPASTDeclarator innerDtor = (ICPPASTDeclarator) ASTQueries.findInnermostDeclarator(declarator); IASTName name = innerDtor.getName(); ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); if (templateDecl != null) { if (templateDecl instanceof ICPPASTTemplateSpecialization) { if (!(function instanceof ICPPTemplateInstance)) return false; if (!((ICPPTemplateInstance) function).isExplicitSpecialization()) return false; } else { if (function instanceof ICPPTemplateDefinition) { final ICPPTemplateDefinition funcTemplate = (ICPPTemplateDefinition) function; if (!isSameTemplateParameterList(funcTemplate.getTemplateParameters(), templateDecl.getTemplateParameters())) { return false; } } else { return false; } } } else if (function instanceof ICPPTemplateDefinition) { return false; } declarator= ASTQueries.findTypeRelevantDeclarator(declarator); if (declarator instanceof ICPPASTFunctionDeclarator) { IType type = function.getType(); return type.isSameType(CPPVisitor.createType(declarator)); } return false; } private static boolean isSameTemplateParameterList(ICPPTemplateParameter[] tplist, ICPPASTTemplateParameter[] tps) { if (tplist.length != tps.length) return false; for (int i = 0; i < tps.length; i++) { if (!isSameTemplateParameter(tplist[i], tps[i])) return false; } return true; } private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) { if (tp1.isParameterPack() != tp2.isParameterPack()) return false; if (tp1 instanceof ICPPTemplateNonTypeParameter) { if (tp2 instanceof ICPPASTParameterDeclaration) { IType t1= ((ICPPTemplateNonTypeParameter) tp1).getType(); IType t2= CPPVisitor.createType((ICPPASTParameterDeclaration) tp2, true); return t1 != null && t1.isSameType(t2); } return false; } if (tp1 instanceof ICPPTemplateTypeParameter) { if (tp2 instanceof ICPPASTSimpleTypeTemplateParameter) { return true; } return false; } if (tp1 instanceof ICPPTemplateTemplateParameter) { if (tp2 instanceof ICPPASTTemplatedTypeTemplateParameter) { final ICPPTemplateTemplateParameter ttp1 = (ICPPTemplateTemplateParameter) tp1; final ICPPASTTemplatedTypeTemplateParameter ttp2 = (ICPPASTTemplatedTypeTemplateParameter) tp2; return isSameTemplateParameterList(ttp1.getTemplateParameters(), ttp2.getTemplateParameters()); } return false; } return false; } static protected IBinding resolveUnknownName(IScope scope, ICPPUnknownBinding unknown) { final IASTName unknownName = unknown.getUnknownName(); LookupData data = new LookupData(unknownName); data.checkPointOfDecl= false; data.typesOnly= unknown instanceof IType; try { // 2: lookup lookup(data, scope); } catch (DOMException e) { data.problem = (ProblemBinding) e.getProblem(); } if (data.problem != null) return data.problem; // 3: resolve ambiguities IBinding binding; try { binding = resolveAmbiguities(data, unknownName); } catch (DOMException e) { binding = e.getProblem(); } // 4: Normal post processing is not possible, because the name is not rooted in AST if (binding == null) binding = new ProblemBinding(unknownName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND); return binding; } }