/******************************************************************************* * Copyright (c) 2004, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Andrew Niefer (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) * Mike Kucera (IBM) * Thomas Corbat (IFS) * Nathan Ridge * Richard Eames *******************************************************************************/ 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.SemanticUtil.ALLCVQ; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ARRAY; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.MPTR; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.PTR; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.calculateInheritanceDepth; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.isConversionOperator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; 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.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; 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.IScope.ScopeLookupData; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration; 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.ICPPASTExpression; 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.ICPPASTLiteralExpression; 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.ICPPASTTranslationUnit; 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.ICPPFunctionInstance; 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.ICPPPartialSpecialization; 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.CollectionUtils; import org.eclipse.cdt.core.parser.util.DebugUtil; import org.eclipse.cdt.core.parser.util.IUnaryPredicate; 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.IASTAmbiguousDeclarator; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.IRecursionResolvingBinding; import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.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.CPPASTTranslationUnit; 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.CPPDeferredConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction; 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.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownField; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMethod; 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.ClassTypeHelper; 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.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluationOwner; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; 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.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; /** * Name resolution. */ public class CPPSemantics { /** * The maximum depth to search ancestors before assuming infinite looping. */ public static final int MAX_INHERITANCE_DEPTH= 40; public static final String EMPTY_NAME = ""; //$NON-NLS-1$ public static final char[] OPERATOR_ = new char[] {'o','p','e','r','a','t','o','r',' '}; public static final IType VOID_TYPE = new CPPBasicType(Kind.eVoid, 0); public static final IType INT_TYPE = new CPPBasicType(Kind.eInt, 0); private static final char[] CALL_FUNCTION = "call-function".toCharArray(); //$NON-NLS-1$ private static final ICPPEvaluation[] NO_INITCLAUSE_EVALUATION = {}; // 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, null); // A regular expression for matching qualified names. This allows for optional global qualification // (leading ::) and then separates the first part of the name from the rest (if present). There are // three capture groups: // (1) If the input name specifies the global namespace (leading ::) then capture group 1 will // be ::. Group 1 will be null otherwise. // (2) The text of the first component of the qualified name, including leading :: if present in // the input string. Leading and trailing whitespace is trimmed. There is no effort to check // that the name contains valid C++ identifier characters. // (3) The text of everything after the first component of the qualified name. // // E.g., -- Input Name -- ---- Capture Groups ---- // "::nsA::nsB::b" => { "::", "nsA", "nsB::b" } // "a" => { null, "a", null } // ":: i" => { "::", "i", null } private static final Pattern QUALNAME_REGEX = Pattern.compile("^\\s*(::)?\\s*([^\\s:]+)\\s*(?:::(.*))?$"); //$NON-NLS-1$ 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.hasTypeOrMemberFunctionOrVariableResult()) { 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); } 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) { final IASTName lookupName = data.getLookupName(); if (lookupName == null) return binding; // If this is the unqualified name of a function in a function call in a template and some // of the function arguments are dependent, a matching function could be found via // argument-dependent lookup at the point of instantiation. if (binding == null || binding instanceof IProblemBinding) { if (!data.qualified && data.isFunctionCall() && CPPTemplates.containsDependentType(data.getFunctionArgumentTypes())) { binding = CPPDeferredFunction.createForName(lookupName.getSimpleID()); } } if (binding instanceof IProblemBinding) return binding; IASTNode lookupPoint = data.getLookupPoint(); 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 = lookupName.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); } catch (DOMException e) { binding = e.getProblem(); } } } // Explicit type conversion in functional notation. if (binding instanceof ICPPClassTemplate && lookupName instanceof ICPPASTTemplateId) { final IASTNode parent = lookupName.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 arguments * enclosed in <>. */ if (binding instanceof ICPPClassTemplate && !(binding instanceof ICPPClassSpecialization) && !(binding instanceof ICPPTemplateParameter) && !(lookupName instanceof ICPPASTTemplateId)) { ASTNodeProperty prop = lookupName.getPropertyInParent(); if (prop != ICPPASTConstructorChainInitializer.MEMBER_ID && prop != ICPPASTTemplateId.TEMPLATE_NAME && !lookupName.isQualified()) { // You cannot use a class template name outside of the class template scope, // mark it as a problem. IBinding user= CPPTemplates.isUsedInClassTemplateScope((ICPPClassTemplate) binding, lookupName); if (user instanceof ICPPClassTemplate) { binding= ((ICPPClassTemplate) user).asDeferredInstance(); } else if (user != null) { binding= user; } else { boolean ok= false; IASTNode node= lookupName.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(lookupName, lookupPoint, 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(), lookupName); if (usedHere instanceof ICPPClassTemplatePartialSpecialization) { if (CPPTemplates.areSameArguments(((ICPPClassTemplatePartialSpecialization) usedHere).getTemplateArguments(), dcl.getTemplateArguments())) binding= ((ICPPClassTemplatePartialSpecialization) usedHere).asDeferredInstance(); } else if (usedHere instanceof ICPPClassTemplate) { if (CPPTemplates.areSameArguments(CPPTemplates.templateParametersAsArguments((ICPPClassTemplate) usedHere), dcl.getTemplateArguments())) { binding= ((ICPPClassTemplate) usedHere).asDeferredInstance(); } } } if (binding instanceof IType) { IType t = getNestedType((IType) binding, TDEF); if (t instanceof ICPPClassType && convertClassToConstructor(lookupName)) { ICPPClassType cls= (ICPPClassType) t; if (cls instanceof IIndexBinding) { cls= data.getTranslationUnit().mapToAST(cls, lookupName); } try { if (lookupName instanceof ICPPASTTemplateId && cls instanceof ICPPClassTemplate) { if (data.getTranslationUnit() != null) { ICPPASTTemplateId id = (ICPPASTTemplateId) lookupName; ICPPTemplateArgument[] args = CPPTemplates.createTemplateArgumentArray(id); IBinding inst= CPPTemplates.instantiate((ICPPClassTemplate) cls, args, lookupPoint); if (inst instanceof ICPPClassType) { cls= (ICPPClassType) inst; } } } if (cls instanceof ICPPUnknownBinding) { binding= new CPPDeferredConstructor(cls); } else { // Do not interpret template arguments to a template class as being // explicit template arguments to its templated constructor. data.setTemplateArguments(null); binding= resolveFunction(data, ClassTypeHelper.getConstructors(cls, lookupPoint), true); } } catch (DOMException e) { return e.getProblem(); } } } IASTName name= lookupName; 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 (namePropertyInParent == IASTNamedTypeSpecifier.NAME) { binding= new CPPUnknownMemberClass(data.skippedScope, name.getSimpleID()); } else if (data.isFunctionCall()) { binding= new CPPUnknownMethod(data.skippedScope, name.getSimpleID()); } else { binding= new CPPUnknownField(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(lookupName, lookupPoint, IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } // Don't create a problem here. } else { binding = new ProblemBinding(lookupName, lookupPoint, 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(lookupName, lookupPoint, 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, lookupName, declaration); if (!(binding instanceof IProblemBinding)) { if (declaration instanceof ICPPASTFunctionDefinition) { ASTInternal.addDefinition(binding, lookupName); } } } // Definitions of static fields. if (binding instanceof ICPPField && lookupName.isDefinition()) { if (declaration.getPropertyInParent() != IASTCompositeTypeSpecifier.MEMBER_DECLARATION) { ASTInternal.addDefinition(binding, lookupName); } } } // If the result is a virtual method called without explicit qualification, and we can determine a // unique final overrider for it in the hierarchy of the method call's implied object type, replace // the method with its final overrider. if (!(lookupName.getParent() instanceof ICPPASTQualifiedName) && binding instanceof ICPPMethod && ((ICPPMethod) binding).isVirtual()) { IType impliedObjectType = data.getImpliedObjectType(); if (impliedObjectType instanceof ICPPClassType) { ICPPMethod finalOverrider = CPPInheritance.getFinalOverrider((ICPPMethod) binding, (ICPPClassType) impliedObjectType, lookupName); if (finalOverrider != null) { binding = finalOverrider; } } } // If we're still null... if (binding == null) { if (name instanceof ICPPASTQualifiedName && declaration != null) { binding = new ProblemBinding(lookupName, lookupPoint, IProblemBinding.SEMANTIC_MEMBER_DECLARATION_NOT_FOUND, data.getFoundBindings()); } else { binding = new ProblemBinding(lookupName, lookupPoint, 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 == 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; } return false; } public static void doKoenigLookup(LookupData data) throws DOMException { data.ignoreUsingDirectives = true; // Set 'qualified' to true for the duration of this function call so the calls to lookup() // don't ascend into enclosing scopes. boolean originalQualified = data.qualified; data.qualified = true; Set<ICPPFunction> friendFns = new HashSet<>(2); Set<ICPPNamespaceScope> associated = getAssociatedScopes(data, friendFns); for (ICPPNamespaceScope scope : associated) { if (!data.visited.containsKey(scope)) { lookup(data, scope); } } Object[] matchingFriendFns = CollectionUtils.filter( friendFns, new NameMatcherPredicate(data.getLookupKey())).toArray(); mergeResults(data, matchingFriendFns, false); data.qualified = originalQualified; } private static class NameMatcherPredicate implements IUnaryPredicate<ICPPFunction> { private char[] fKey; public NameMatcherPredicate(char[] key) { fKey = key; } @Override public boolean apply(ICPPFunction argument) { return Arrays.equals(argument.getNameCharArray(), fKey); } } 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.qualified = 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, NO_INITCLAUSE_EVALUATION); } 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, Set<ICPPFunction> friendFns) { if (!data.hasFunctionArguments()) return Collections.emptySet(); IType[] ps = data.getFunctionArgumentTypes(); Set<ICPPNamespaceScope> namespaces = new HashSet<>(2); ObjectSet<IType> handled = new ObjectSet<>(2); for (IType p : ps) { try { getAssociatedScopes(p, namespaces, friendFns, handled, data.getTranslationUnit(), true); } catch (DOMException e) { } } IASTName lookupName= data.getLookupName(); if (lookupName != null) { final char[] simpleID = lookupName.getSimpleID(); if (CharArrayUtils.equals(CPPVisitor.BEGIN, simpleID) || CharArrayUtils.equals(CPPVisitor.END, simpleID)) { IASTNode parent = lookupName.getParent(); // id-expression if (parent != null) parent= parent.getParent(); // function call if (parent != null) parent= parent.getParent(); // the loop if (parent instanceof ICPPASTRangeBasedForStatement) { IASTTranslationUnit tu = parent.getTranslationUnit(); IBinding[] std= tu.getScope().find(CPPVisitor.STD, tu); 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, Set<ICPPFunction> friendFns, ObjectSet<IType> handled, CPPASTTranslationUnit tu, boolean lookInBaseClasses) throws DOMException { t = getNestedType(t, TDEF | CVTYPE | PTR | ARRAY | REF); // No point getting namespaces associated with a dependent type - we don't know what they // are yet. if (CPPTemplates.isDependentType(t)) return; if (t instanceof IBinding) { if (handled.containsKey(t)) return; handled.put(t); if (t instanceof IEnumeration) { // [basic.lookup.argdep] p2.3: an enumeration's only associated namespace // is the innermost enclosing namespace of its declaration. getAssociatedNamespaceScopes(getContainingNamespaceScope((IBinding) t, tu), namespaces); } else { IBinding owner= ((IBinding) t).getOwner(); if (owner instanceof ICPPClassType) { getAssociatedScopes((IType) owner, namespaces, friendFns, handled, tu, false /* do not look at base classes of the enclosing class */); } else { getAssociatedNamespaceScopes(getContainingNamespaceScope((IBinding) t, tu), namespaces); } } } if (t instanceof ICPPClassType && !(t instanceof ICPPClassTemplate)) { ICPPClassType ct= (ICPPClassType) t; if (lookInBaseClasses) { ICPPBase[] bases = ClassTypeHelper.getBases(ct, tu); for (ICPPBase base : bases) { IBinding b = base.getBaseClass(); if (b instanceof IType) getAssociatedScopes((IType) b, namespaces, friendFns, handled, tu, true); } } // 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 ICPPSpecialization) { for (IBinding friend : ClassTypeHelper.getFriends(ct, tu)) { if (friend instanceof ICPPFunction) { friendFns.add((ICPPFunction) friend); } } if (ct instanceof ICPPTemplateInstance) { ICPPTemplateArgument[] args = ((ICPPTemplateInstance) ct).getTemplateArguments(); for (ICPPTemplateArgument arg : args) { if (arg.isTypeValue()) { getAssociatedScopes(arg.getTypeValue(), namespaces, friendFns, handled, tu, true); } } } } } else if (t instanceof IFunctionType) { IFunctionType ft = (IFunctionType) t; getAssociatedScopes(ft.getReturnType(), namespaces, friendFns, handled, tu, true); IType[] ps = ft.getParameterTypes(); for (IType pt : ps) { getAssociatedScopes(pt, namespaces, friendFns, handled, tu, true); } } else if (t instanceof ICPPPointerToMemberType) { final ICPPPointerToMemberType pmt = (ICPPPointerToMemberType) t; getAssociatedScopes(pmt.getMemberOfClass(), namespaces, friendFns, handled, tu, true); getAssociatedScopes(pmt.getType(), namespaces, friendFns, handled, tu, true); } else if (t instanceof FunctionSetType) { FunctionSetType fst= (FunctionSetType) t; for (ICPPFunction fn : fst.getFunctionSet().getBindings()) { getAssociatedScopes(fn.getType(), namespaces, friendFns, handled, tu, true); } } } private static ICPPNamespaceScope getContainingNamespaceScope(IBinding binding, CPPASTTranslationUnit tu) throws DOMException { if (binding == null) return null; IScope scope = binding.getScope(); scope = SemanticUtil.mapToAST(scope, tu); 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) 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 = n.getLastName(); } scope = CPPVisitor.getContainingScope(n); } else { scope = CPPVisitor.getContainingScope(name); } 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 { @SuppressWarnings("unchecked") final CharArrayObjectMap<Object> oldItems = (CharArrayObjectMap<Object>) data.foundItems; data.foundItems = mergePrefixResults(oldItems, results, scoped); } } /** * @param dest * @param source : either Object[] or CharArrayObjectMap * @param scoped * @return */ static CharArrayObjectMap<Object> mergePrefixResults(CharArrayObjectMap<Object> dest, Object source, boolean scoped) { if (source == null) return dest; CharArrayObjectMap<Object> resultMap = (dest != null) ? dest : new CharArrayObjectMap<>(2); CharArrayObjectMap<Object> map = null; Object[] objs = null; int size; if (source instanceof CharArrayObjectMap) { @SuppressWarnings("unchecked") final CharArrayObjectMap<Object> sourceMap = (CharArrayObjectMap<Object>) source; map = sourceMap; 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; } /** * 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 (start == null && lookupDestructor(data)) { return; } ICPPScope nextScope= null; ICPPTemplateScope nextTmplScope= null; if (start instanceof ICPPScope) { nextScope= (ICPPScope) start; } else { IASTName lookupName= data.getLookupName(); if (lookupName == null) return; nextScope= getLookupScope(lookupName); if (nextScope instanceof ICPPTemplateScope) { nextTmplScope= (ICPPTemplateScope) nextScope; nextScope= getParentScope(nextScope, data.getTranslationUnit()); } else { nextTmplScope= enclosingTemplateScope(lookupName); } if (data.qualified && nextTmplScope != null) { nextTmplScope= null; if (dependsOnTemplateFieldReference(lookupName)) { data.setIgnorePointOfDeclaration(true); } } } 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) { } } 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; scope = (ICPPScope) SemanticUtil.mapToAST(scope, data.getTranslationUnit()); if (!data.usingDirectivesOnly && !(data.ignoreMembers && scope instanceof ICPPClassScope)) { mergeResults(data, getBindingsFromScope(scope, data), true); // Nominate using-directives found in this block or namespace. if (scope instanceof ICPPNamespaceScope) { final ICPPNamespaceScope namespaceScope= (ICPPNamespaceScope) scope; if (data.qualified && namespaceScope.getKind() != EScopeKind.eLocal) { lookupInlineNamespaces(data, namespaceScope); } if (data.contentAssist || !data.hasResults() || !data.qualified) { // Nominate namespaces nominateNamespaces(data, namespaceScope); } } } // Lookup in nominated namespaces if (!data.ignoreUsingDirectives && scope instanceof ICPPNamespaceScope && !(scope instanceof ICPPBlockScope)) { if (!data.hasResults() || !data.qualified || data.contentAssist) { lookupInNominated(data, (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); 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.getTranslationUnit()); } } } /** * 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; CPPASTTranslationUnit tu = data.getTranslationUnit(); if (!isFromIndex(binding) || tu == null || isReachableFromAst(tu, binding)) { return true; } } } } return false; } private static void lookupInlineNamespaces(LookupData data, ICPPNamespaceScope namespace) throws DOMException { lookupInlineNamespaces(data, namespace, new HashSet<ICPPInternalNamespaceScope>()); } private static void lookupInlineNamespaces(LookupData data, ICPPNamespaceScope namespace, Set<ICPPInternalNamespaceScope> visited) throws DOMException { if (namespace instanceof ICPPInternalNamespaceScope) { ICPPInternalNamespaceScope ns= (ICPPInternalNamespaceScope) namespace; visited.add(ns); for (ICPPInternalNamespaceScope inline : ns.getInlineNamespaces()) { if (visited.contains(inline)) { CCorePlugin.log(IStatus.WARNING, "Detected circular reference between inline namespaces"); //$NON-NLS-1$ continue; } mergeResults(data, getBindingsFromScope(inline, data), true); lookupInlineNamespaces(data, inline, visited); 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. CPPASTTranslationUnit tu= data.getTranslationUnit(); if (tu != null) { tu.handleAdditionalDirectives(blockScope); } } ICPPUsingDirective[] uds= blockScope.getUsingDirectives(); if (uds != null && uds.length > 0) { HashSet<ICPPNamespaceScope> handled= new HashSet<>(); for (final ICPPUsingDirective ud : uds) { if (data.isIgnorePointOfDeclaration() || declaredBefore(ud, data.getLookupPoint(), false)) { storeUsingDirective(data, blockScope, ud, handled); } } } } private static boolean lookupDestructor(LookupData data) throws DOMException { IASTName typeDtorName= data.getLookupName(); if (typeDtorName == null) return false; 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. IASTNode parent= typeDtorName.getParent(); if (parent instanceof ICPPASTQualifiedName) { ICPPASTQualifiedName dqname= (ICPPASTQualifiedName) parent; if (dqname.getLastName() != typeDtorName) return false; } char[] tchars= new char[typeDtorChars.length - 1]; System.arraycopy(typeDtorChars, 1, tchars, 0, tchars.length); LookupData ld2= new LookupData(tchars, data.getTemplateArguments(), data.getLookupPoint()); ld2.setIgnorePointOfDeclaration(data.isIgnorePointOfDeclaration()); ld2.contentAssist= data.contentAssist; ld2.fNoNarrowing= data.fNoNarrowing; ld2.fHeuristicBaseLookup= data.fHeuristicBaseLookup; ld2.qualified= parent instanceof ICPPASTQualifiedName; ld2.typesOnly= true; lookup(ld2, getLookupScope(typeDtorName)); IBinding[] typedefs = ld2.getFoundBindings(); if (typedefs.length < 1 || !(typedefs[0] instanceof ITypedef)) return false; IType t= SemanticUtil.getNestedType((ITypedef) typedefs[0], 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); data.setLookupKey(classDtorChars); lookup(data, scope); 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 ICPPASTLiteralExpression) { final ICPPASTLiteralExpression litExpr = (ICPPASTLiteralExpression) expression; if (litExpr.getKind() == IASTLiteralExpression.lk_this) { final IType thisType = SemanticUtil.getNestedType(((ICPPEvaluationOwner) litExpr).getEvaluation().getType(litExpr), 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, LookupData data) throws DOMException { IBinding[] bindings= scope.getBindings(data); if (scope instanceof ICPPASTInternalScope && scope instanceof ICPPClassScope) { final IASTName lookupName = data.getLookupName(); if (LookupData.checkWholeClassScope(lookupName)) { // Bug 103857: Members declared after the point of completion cannot be // found in the partial AST, we look them up in the index CPPASTTranslationUnit tu = data.getTranslationUnit(); if (tu != null && tu.isForContentAssist()) { IIndex index = tu.getIndex(); IASTNode node = ((IASTInternalScope) scope).getPhysicalNode(); if (index != null && node != null && node.contains(lookupName)) { IBinding indexBinding= index.adaptBinding(((ICPPClassScope) scope).getClassType()); if (indexBinding instanceof ICPPClassType) { IScope scopeInIndex= ((ICPPClassType) indexBinding).getCompositeScope(); bindings= ArrayUtil.addAll(bindings, scopeInIndex.getBindings(data)); } } } } } if (data.ignoreRecursionResolvingBindings()) { bindings = ArrayUtil.filter(bindings, new RecursionResolvingBindingFilter()); } return expandUsingDeclarationsAndRemoveObjects(bindings, data); } private static class RecursionResolvingBindingFilter implements IUnaryPredicate<IBinding> { @Override public boolean apply(IBinding argument) { return !(argument instanceof IRecursionResolvingBinding); } } private static IBinding[] expandUsingDeclarationsAndRemoveObjects(final IBinding[] bindings, LookupData data) { if (bindings == null || bindings.length == 0) return IBinding.EMPTY_BINDING_ARRAY; for (IBinding b : bindings) { if (b == null) break; if (b instanceof ICPPUsingDeclaration || (data.typesOnly && isObject(b))) { List<IBinding> result= new ArrayList<>(bindings.length); expandUsingDeclarations(bindings, data, 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, LookupData data, List<IBinding> result) { if (bindings != null) { for (IBinding b : bindings) { if (b == null) return; // Lookup for a declaration shall ignore the using declarations. if (b instanceof ICPPUsingDeclaration) { if (data.forDeclaration() == null) { for (IBinding d : ((ICPPUsingDeclaration) b).getDelegates()) { // Note on excluding constructors: // Constructors are never found during name lookup ([class.ctor] p2). // Binding resolution sometimes resolves names to constructors, and as // such, the delegates of a using-declaration can include constructors, // but when using these delegates in the process of name lookup, // constructors are ignored. If the binding resolution triggering this // name lookup wants to ultimately resolve to a constructor, it can do so // after the name lookup phase, e.g. in the convertClassToConstructor() // call in postResolution(). if (d != null && !(data.typesOnly && isObject(d)) && !(d instanceof ICPPConstructor)) { result.add(d); } } } } else if (!(data.typesOnly && 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.getQualifier()[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, IASTTranslationUnit unit) throws DOMException { IScope parentScope= scope.getParent(); // The index cannot return the translation unit as parent scope. if (parentScope == null && scope instanceof ICPPClassSpecializationScope && unit instanceof CPPASTTranslationUnit) { parentScope = unit.getScope(); } else { parentScope = SemanticUtil.mapToAST(parentScope, unit); } 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(); CPPASTTranslationUnit tu= data.getTranslationUnit(); if (tu != null) { nominated= (ICPPNamespaceScope) tu.mapToASTScope(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, 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<>(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 (tu != null) { 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, ICPPASTTranslationUnit tu) throws DOMException { ObjectSet<IScope> set = new ObjectSet<>(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 ICPPASTSwitchStatement) { nodes = new IASTNode[] { ((ICPPASTSwitchStatement) parent).getControllerDeclaration() }; } else if (parent instanceof ICPPASTIfStatement) { nodes = new IASTNode[] { ((ICPPASTIfStatement) parent).getConditionDeclaration() }; } else if (parent instanceof ICPPASTWhileStatement) { nodes = new IASTNode[] { ((ICPPASTWhileStatement) parent).getConditionDeclaration() }; } 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 = 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 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(); handleEnumeration(enumeration, scope); } 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; default: break; } } } else if (declaration instanceof ICPPASTUsingDeclaration) { ICPPASTUsingDeclaration using = (ICPPASTUsingDeclaration) declaration; IASTName name = using.getName(); if (name instanceof ICPPASTQualifiedName) { name = 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 ICPPASTAliasDeclaration) { ICPPASTAliasDeclaration aliasDecl = (ICPPASTAliasDeclaration) declaration; IASTName alias = aliasDecl.getAlias(); ASTInternal.addName(scope, alias); // The mapping-type-id could declare an enumeration. IASTDeclSpecifier declSpec = aliasDecl.getMappingTypeId().getDeclSpecifier(); if (declSpec instanceof ICPPASTEnumerationSpecifier) { handleEnumeration((ICPPASTEnumerationSpecifier) declSpec, scope); } } 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; default: break; } } } private static void handleEnumeration(ICPPASTEnumerationSpecifier enumSpec, IScope enclosingScope) { // Add unscoped enumerators to the enclosing scope if (!enumSpec.isScoped()) { for (IASTEnumerator enumerator : enumSpec.getEnumerators()) { ASTInternal.addName(enclosingScope, enumerator.getName()); } } } /** * 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. */ private static void lookupInNominated(LookupData data, 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, 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) { final CPPASTTranslationUnit tu = data.getTranslationUnit(); if (tu != null) { 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; } } LookupData data = createLookupData(name); data.foundItems = bindings; try { return resolveAmbiguities(data); } catch (DOMException e) { return e.getProblem(); } // // IBinding[] result = null; // for (Object binding : bindings) { // if (binding instanceof IASTName) { // result = ArrayUtil.append(IBinding.class, result, ((IASTName) binding).resolveBinding()); // } else if (binding instanceof IBinding) { // result = ArrayUtil.append(IBinding.class, result, (IBinding) binding); // } // } // return new CPPCompositeBinding(result); } public static boolean declaredBefore(Object obj, IASTNode node, boolean indexBased) { if (node == null) return true; final int pointOfRef= ((ASTNode) node).getOffset(); ASTNode nd = null; if (obj instanceof ICPPSpecialization) { obj = ((ICPPSpecialization) obj).getSpecializedBinding(); } int pointOfDecl= -1; boolean pointOfDeclIsEndOffset = false; if (obj instanceof ICPPInternalBinding) { ICPPInternalBinding cpp = (ICPPInternalBinding) obj; IASTNode[] n = cpp.getDeclarations(); if (n != null && n.length > 0) { nd = (ASTNode) n[0]; } ASTNode def = (ASTNode) cpp.getDefinition(); if (def != null && (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(); // [basic.scope.pdecl]/p9: The point of declaration for a template parameter // is immediately after its complete template-parameter. // Note: can't just check "dtor.getParent() instanceof ICPPASTTemplateParameter" // because function parameter declarations implement ICPPASTTemplateParameter too. boolean isTemplateParameter = dtor.getParent() instanceof ICPPASTTemplateParameter && dtor.getParent().getPropertyInParent() == ICPPASTTemplateDeclaration.PARAMETER; if (init != null && !isTemplateParameter) { pointOfDecl = ((ASTNode) init).getOffset() - 1; } else { pointOfDecl = ((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength(); pointOfDeclIsEndOffset = true; } } 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(); } pointOfDeclIsEndOffset = true; } 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(); pointOfDeclIsEndOffset = true; } else if (prop == ICPPASTAliasDeclaration.ALIAS_NAME) { // [basic.scope.pdecl]/p3: The point of declaration of an alias or alias template // immediately follows the type-id to which the alias refers. ASTNode targetType = (ASTNode) ((ICPPASTAliasDeclaration) nd.getParent()).getMappingTypeId(); pointOfDecl = targetType.getOffset() + targetType.getLength(); pointOfDeclIsEndOffset = true; } else if (prop == ICPPASTSimpleTypeTemplateParameter.PARAMETER_NAME || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER_NAME) { // [basic.scope.pdecl]/p9: The point of declaration for a template parameter // is immediately after its complete template-parameter. // Type and template template parameters are handled here; // non-type template parameters are handled in the DECLARATOR_NAME // case above. nd = (ASTNode) nd.getParent(); pointOfDecl = nd.getOffset() + nd.getLength(); pointOfDeclIsEndOffset = true; } else { pointOfDecl = nd.getOffset() + nd.getLength(); pointOfDeclIsEndOffset = true; } } return pointOfDecl < pointOfRef || (pointOfDecl == pointOfRef && pointOfDeclIsEndOffset); } 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) && scope instanceof ICPPNamespaceScope) { return true; } } else if (cpp instanceof ICompositeType || cpp instanceof IEnumeration) { IScope scope= cpp.getScope(); if (!(scope instanceof ICPPBlockScope) && 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) throws DOMException { if (!data.hasResults() || data.contentAssist) return null; final IASTName lookupName = data.getLookupName(); IASTNode lookupPoint = data.getLookupPoint(); final boolean indexBased= data.getIndex() != null; final boolean checkWholeClass= lookupName == null || LookupData.checkWholeClassScope(lookupName); ObjectSet<ICPPFunction> fns= ObjectSet.emptySet(); IBinding type = null; IBinding obj = null; boolean ambiguous = false; IBinding temp = null; final CPPASTTranslationUnit tu = data.getTranslationUnit(); Object[] items = (Object[]) data.foundItems; for (int i = 0; i < items.length && items[i] != null; i++) { Object o = items[i]; boolean declaredBefore = data.isIgnorePointOfDeclaration() || declaredBefore(o, lookupPoint, indexBased); boolean checkResolvedNamesOnly= false; if (!checkWholeClass && !declaredBefore) { if (lookupName != null && lookupName.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; } // Specializations are selected during instantiation. if (temp instanceof ICPPPartialSpecialization) continue; if (temp instanceof ICPPTemplateInstance && lookupName instanceof ICPPASTTemplateId) { temp= ((ICPPTemplateInstance) temp).getSpecializedBinding(); if (!(temp instanceof IType)) 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<>(2); fns.put((ICPPFunction) temp); } else if (temp instanceof IType) { if (type == null) { type = temp; ambiguous = false; } else if (!type.equals(temp)) { int c = compareByRelevance(tu, type, temp); if (c < 0) { type= temp; ambiguous = false; } 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; ambiguous = false; } } else { ambiguous = true; } } } } else { if (obj == null) { obj = temp; ambiguous = false; } else if (!obj.equals(temp)) { if (obj instanceof ICPPNamespace && temp instanceof ICPPNamespace && SemanticUtil.isSameNamespace((ICPPNamespace) obj, (ICPPNamespace) temp)) { continue; } int c = compareByRelevance(tu, obj, temp); if (c < 0) { obj= temp; ambiguous = false; } else if (c == 0) { ambiguous = true; } } } } if (ambiguous) { return new ProblemBinding(lookupName, lookupPoint, 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(lookupName, lookupPoint, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings()); } } } IBinding[] bindings = IBinding.EMPTY_BINDING_ARRAY; if (cmp > 0) { bindings = ArrayUtil.append(bindings, obj); bindings = ArrayUtil.append(bindings, type); } else { bindings = ArrayUtil.append(bindings, type); bindings = ArrayUtil.addAll(bindings, fns.keyArray()); } bindings = ArrayUtil.trim(IBinding.class, bindings); ICPPUsingDeclaration composite = new CPPUsingDeclaration(lookupName, bindings); return composite; } if (obj != null && type != null) { if (obj instanceof ICPPNamespace) { if (compareByRelevance(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.isEmpty()) { 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(lookupName, lookupPoint, 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) return false; final CPPASTTranslationUnit tu = data.getTranslationUnit(); if (tu != null) { return !isReachableFromAst(tu, b2) && isReachableFromAst(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) return false; final CPPASTTranslationUnit tu = data.getTranslationUnit(); for (int i = 0; i < fns.length; i++) { if (!isFromIndex(fns[i])) { return false; // function from ast } } if (!isReachableFromAst(tu, type)) { return false; } for (IFunction fn : fns) { if (isReachableFromAst(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. final CPPASTTranslationUnit tu = data.getTranslationUnit(); if (tu != null) { boolean b1Reachable= isReachableFromAst(tu, b1); boolean b2Reachable= isReachableFromAst(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 final CPPASTTranslationUnit tu = data.getTranslationUnit(); if (!isReachableFromAst(tu, obj)) { return -1; // obj not reachable } for (IFunction fn : fns) { if (isReachableFromAst(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(); IIndexFileSet astFileSet = ast.getASTFileSet(); return indexFileSet != null && (indexFileSet.containsDeclaration(indexBinding) || astFileSet.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; final int argumentCount = data.getFunctionArgumentCount(); final int packExpansionCount= data.getFunctionArgumentPackExpansionCount(); // 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 - packExpansionCount > numPars) { // More arguments than parameters --> need ellipsis or parameter pack ok= fn.takesVarArgs() || fn.hasParameterPack(); } else { ok = numArgs >= fn.getRequiredArgumentCount() || packExpansionCount > 0; } 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 { final IASTName lookupName = data.getLookupName(); if (fns == null || fns.length == 0 || fns[0] == null) return null; fns= ArrayUtil.trim(fns); sortAstBeforeIndex(fns); if (data.forUsingDeclaration) return new CPPUsingDeclaration(lookupName, fns); if (lookupName instanceof ICPPASTConversionName) { return resolveUserDefinedConversion(data, fns); } if (data.forDeclaration() != null) { return resolveFunctionDeclaration(data, fns); } // No arguments to resolve function final IASTNode lookupPoint = data.getLookupPoint(); if (!data.hasFunctionArguments()) { return createFunctionSet(fns, data.getTemplateArguments(), lookupPoint, lookupName); } // 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); if (tmp.length == 0 || tmp[0] == null) return new ProblemBinding(lookupName, lookupPoint, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, fns); tmp= CPPTemplates.instantiateForFunctionCall(tmp, data.getTemplateArguments(), Arrays.asList(argTypes), Arrays.asList(data.getFunctionArgumentValueCategories()), data.argsContainImpliedObject, lookupPoint); if (tmp.length == 0 || tmp[0] == null) return new ProblemBinding(lookupName, lookupPoint, 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(lookupName, lookupPoint, 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 CPPDeferredFunction.createForCandidates(fns); } IFunction[] ambiguousFunctions= null; // Ambiguity, two or more functions are equally good. FunctionCost bestFnCost = null; // The cost of the best function. // Loop over all functions List<FunctionCost> potentialCosts= null; ICPPFunction unknownFunction= null; final CPPASTTranslationUnit tu = data.getTranslationUnit(); for (ICPPFunction fn : fns) { if (fn == null) continue; UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN; final FunctionCost fnCost= costForFunctionCall(fn, udc, data); if (fnCost == null) continue; if (fnCost == CONTAINS_DEPENDENT_TYPES) { if (viableCount == 1) return fn; unknownFunction = fn; continue; } if (fnCost.hasDeferredUDC()) { if (potentialCosts == null) { potentialCosts= new ArrayList<>(); } potentialCosts.add(fnCost); continue; } int cmp= fnCost.compareTo(tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; } else if (cmp == 0) { ambiguousFunctions= ArrayUtil.append(IFunction.class, ambiguousFunctions, fn); } } if (potentialCosts != null) { for (FunctionCost fnCost : potentialCosts) { if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC(lookupPoint)) { int cmp= fnCost.compareTo(tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; } else if (cmp == 0) { ambiguousFunctions= ArrayUtil.append(IFunction.class, ambiguousFunctions, fnCost.getFunction()); } } } } if (bestFnCost == null) { if (unknownFunction == null) return null; setTargetedFunctionsToUnknown(argTypes); return CPPDeferredFunction.createForCandidates(fns); } if (ambiguousFunctions != null) { ambiguousFunctions= ArrayUtil.append(IFunction.class, ambiguousFunctions, bestFnCost.getFunction()); return new ProblemBinding(lookupName, lookupPoint, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, ambiguousFunctions); } if (bestFnCost.hasAmbiguousUserDefinedConversion()) { return new ProblemBinding(lookupName, lookupPoint, 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(ICPPFunction[] fns, ICPPTemplateArgument[] args, IASTNode point, IASTName name) { // First try to find a unique function if (name != null && name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { name= (IASTName) name.getParent(); } ICPPFunction f= getUniqueFunctionForSet(fns, args, point); return f == null ? new CPPFunctionSet(fns, args, name) : f; } private static ICPPFunction getUniqueFunctionForSet(ICPPFunction[] fns, ICPPTemplateArgument[] args, IASTNode point) { // First try to find a unique function ICPPFunction result= null; boolean haveASTResult= false; for (ICPPFunction f : fns) { // Use the ast binding final boolean fromIndex = isFromIndex(f); if (haveASTResult && fromIndex) break; boolean isCandidate; if (f instanceof ICPPFunctionTemplate) { if (args == null) { isCandidate= true; } else { // See 14.3-7 ICPPFunctionTemplate funcTemp = (ICPPFunctionTemplate) f; final ICPPTemplateParameter[] tpars = funcTemp.getTemplateParameters(); final CPPTemplateParameterMap map = new CPPTemplateParameterMap(tpars.length); if (!TemplateArgumentDeduction.addExplicitArguments(funcTemp, tpars, args, map, point)) { isCandidate= false; } else { f = CPPTemplates.instantiateForAddressOfFunction(funcTemp, null, args, point); isCandidate= f != null; } } } else { isCandidate= args == null; } if (isCandidate) { if (result != null) return null; result= f; haveASTResult= !fromIndex; } } if (result instanceof ICPPFunctionTemplate) return CPPTemplates.instantiateForAddressOfFunction((ICPPFunctionTemplate) result, null, args, point); 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.getLookupName(); 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.getTranslationUnit(); 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)) { // If the declared function type is dependent, there is no point trying to use it // to instantiate the template, so return a deferred function instead. // Note that CPPTemplates.instantiateForFunctionCall() behaves similarly. if (CPPTemplates.isDependentType(ft)) { return CPPDeferredFunction.createForCandidates(fns); } ICPPFunctionTemplate template= (ICPPFunctionTemplate) fn; ICPPFunction inst= CPPTemplates.instantiateForFunctionDeclaration(template, tmplArgs, ft, data.getLookupPoint()); if (inst != null) { int cmp= CPPTemplates.orderFunctionTemplates(bestTemplate, template, TypeSelection.PARAMETERS_AND_RETURN_TYPE, data.getLookupPoint()); 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.getLookupName(), data.getLookupPoint(), 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, UDCMode udc, LookupData data) throws DOMException { IType[] argTypes= data.getFunctionArgumentTypes(); ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories(); int skipArg= 0; final ICPPFunctionType ftype= fn.getType(); if (ftype == null) return null; IType implicitParameterType= null; IType impliedObjectType= null; ValueCategory impliedObjectValueCategory= null; final IType[] paramTypes= ftype.getParameterTypes(); if (fn instanceof ICPPMethod && !(fn instanceof ICPPConstructor)) { implicitParameterType = getImplicitParameterType((ICPPMethod) fn); if (data.argsContainImpliedObject) { impliedObjectType= argTypes[0]; impliedObjectValueCategory= argValueCategories[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, data.getLookupPoint()); } else { result= new FunctionCost(fn, sourceLen + 1, data.getLookupPoint()); if (impliedObjectType == null) { impliedObjectType= data.getImpliedObjectType(); } if (impliedObjectValueCategory == null) { impliedObjectValueCategory= data.getImpliedObjectValueCategory(); if (impliedObjectValueCategory == null) impliedObjectValueCategory= ValueCategory.LVALUE; } 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 { Context context = ftype.hasRefQualifier() ? Context.IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER : Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER; cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, impliedObjectValueCategory, UDCMode.FORBIDDEN, context, data.getLookupPoint()); 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, data.getLookupPoint()) >= 0) return null; return CONTAINS_DEPENDENT_TYPES; } } } if (!cost.converts()) return null; result.setCost(k++, cost, impliedObjectValueCategory); } for (int j = 0; j < sourceLen; j++) { final IType argType= SemanticUtil.getNestedType(argTypes[j + skipArg], TDEF | REF); if (argType == null) return null; final ValueCategory argValueCategory = argValueCategories[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, argValueCategory); continue; } if (argType instanceof FunctionSetType) { cost= ((FunctionSetType) argType).costForTarget(paramType, data.getLookupPoint()); } 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, argValueCategory, udc, ctx, data.getLookupPoint()); if (data.fNoNarrowing && cost.isNarrowingConversion(data.getLookupPoint())) { cost= Cost.NO_CONVERSION; } } if (!cost.converts()) return null; result.setCost(k++, cost, argValueCategory); } return result; } static IType getImplicitParameterType(ICPPMethod m) { IType implicitType; ICPPClassType owner= m.getClassOwner(); if (owner instanceof ICPPClassTemplate) { owner= (ICPPClassType) ((ICPPClassTemplate) owner).asDeferredInstance(); } ICPPFunctionType ft= m.getType(); implicitType= SemanticUtil.addQualifiers(owner, ft.isConst(), ft.isVolatile(), false); return new CPPReferenceType(implicitType, ft.isRValueReference()); } private static IBinding resolveUserDefinedConversion(LookupData data, ICPPFunction[] fns) { ICPPASTConversionName astName= (ICPPASTConversionName) data.getLookupName(); IType t= CPPVisitor.createType(astName.getTypeId()); if (t instanceof ISemanticProblem) { return new ProblemBinding(astName, data.getLookupPoint(), IProblemBinding.SEMANTIC_INVALID_TYPE, data.getFoundBindings()); } if (data.forDeclaration() == null || data.forExplicitFunctionSpecialization() || data.forExplicitFunctionInstantiation()) { fns= CPPTemplates.instantiateConversionTemplates(fns, t, data.getLookupPoint()); } 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, data.getLookupPoint(), 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, CPPFunctionSet functionSet) { 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 = resolveFunction(data, ClassTypeHelper.getConstructors((ICPPClassType) targetType, name), 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 ICPPASTExpression && 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; // If we're in a dependent context, we don't have enough information // to resolve the function set. if (((ICPPEvaluationOwner) parent).getEvaluation().isTypeDependent()) { return CPPDeferredFunction.createForCandidates(functionSet.getBindings()); } } ICPPFunction function = resolveTargetedFunction(targetType, functionSet, name); if (function == null) return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD); return function; } private static boolean isViableUserDefinedLiteralOperator(IBinding binding, int kind) { if (binding == null || binding instanceof ProblemBinding) { return false; } if (binding instanceof ICPPFunction) { ICPPFunction func = (ICPPFunction) binding; if (func.getRequiredArgumentCount() == 1) { IType type = null; if (kind == IASTLiteralExpression.lk_integer_constant) { type = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG); } else if (kind == IASTLiteralExpression.lk_float_constant) { type = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG); } return func.getParameters()[0].getType().isSameType(type); } } return false; } /** * Given a LiteralExpression with a user-defined literal suffix, * finds the corresponding defined operator. * Tries to implement 2.14.8.(2-10) * @param exp <code>IASTLiteralExpression</code> which has a user-defined literal suffix * @return CPPFunction or null * @throws DOMException */ public static IBinding findUserDefinedLiteralOperator(IASTLiteralExpression exp) throws DOMException { IBinding ret = null; /* * 2.14.8.2 * Let `IASTLiteralExpression exp` = L * Let `exp.getSuffix()` = X * Let `bindings` = S * A user-defined-literal is treated as a call to a literal operator or * literal operator template (13.5.8). To determine the form of this * call for a given user-defined-literal L with ud-suffix X, the * literal-operator-id whose literal suffix identifier is X is looked up * in the context of L using the rules for unqualified name lookup (3.4.1). * Let S be the set of declarations found by this lookup. * S shall not be empty. * */ int kind = exp.getKind(); IBinding[] bindings = findBindings(exp.getTranslationUnit().getScope(), ((CPPASTLiteralExpression) exp).getOperatorName(), false); ICPPFunction[] funcs = new ICPPFunction[bindings.length]; ICPPFunctionTemplate[] tplFunctions = new ICPPFunctionTemplate[bindings.length]; LookupData data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp); int i = 0, j = 0; for (IBinding binding : bindings) { if (binding instanceof ICPPFunction || binding instanceof ICPPFunctionTemplate) { funcs[i++] = (ICPPFunction) binding; if (binding instanceof ICPPFunctionTemplate) { tplFunctions[j++] = (ICPPFunctionTemplate) binding; } } } funcs = ArrayUtil.trim(funcs, i); tplFunctions = ArrayUtil.trim(tplFunctions, j); if (funcs.length == 0) { // S shall not be empty return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_NAME_NOT_FOUND); } if (kind == IASTLiteralExpression.lk_integer_constant || kind == IASTLiteralExpression.lk_float_constant) { if (kind == IASTLiteralExpression.lk_integer_constant) { /* * 2.14.8.3 * Let `exp.getValue()` = n * If L is a user-defined-integer-literal, let n be the literal * without its ud-suffix. If S contains a literal operator with * parameter type unsigned long long, then use operator "" X(n ULL) */ CPPBasicType t = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG, exp); data.setFunctionArguments(false, createArgForType(exp, t)); ret = resolveFunction(data, funcs, true); if (isViableUserDefinedLiteralOperator(ret, kind)) { return ret; } } else if (kind == IASTLiteralExpression.lk_float_constant) { /* * 2.14.8.4 * Let `exp.getValue()` = f * If L is a user-defined-floating-literal, let f be the literal * without its ud-suffix. If S contains a literal operator with * parameter type long double, then use operator "" X(f L) */ CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp); data.setFunctionArguments(false, createArgForType(exp, t)); ret = resolveFunction(data, funcs, true); if (isViableUserDefinedLiteralOperator(ret, kind)) { return ret; } } /* * 2.14.8.3 (cont.), 2.14.8.4 (cont.) * Otherwise, S shall contain a raw literal operator or a literal * operator template but not both. */ // Raw literal operator `operator "" _op(const char * c)` CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false); data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp); data.setFunctionArguments(false, createArgForType(exp, charArray)); ret = resolveFunction(data, funcs, true); // char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator // The string literal is passed to the operator as chars: // "literal"_op -> operator "" _op<'l', 'i', 't', 'e', 'r', 'a', 'l'>(); ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length]; for (int k = 0; k < stringLiteral.length; k++) { args[k] = new CPPTemplateNonTypeArgument(new EvalFixed(CPPBasicType.CHAR, PRVALUE, IntegralValue.create(stringLiteral[k])), exp); } data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp); IBinding litTpl = resolveFunction(data, tplFunctions, true); // Do we have valid template and non-template bindings? if (ret != null && !(ret instanceof IProblemBinding)) { // Do we have valid template and non-template bindings? if (litTpl instanceof ICPPFunctionInstance) { // Ambiguity? It has two valid options, and the spec says it shouldn't return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, tplFunctions); } } else { if (litTpl instanceof ICPPFunctionInstance) { // Only the template binding is valid ret = litTpl; } else { // Couldn't find a valid operator return ret; } } } else if (kind == IASTLiteralExpression.lk_string_literal) { /* * 2.14.8.5 * If L is a user-defined-string-literal, let str be the literal * without its ud-suffix and let len be the number of code units in * str (i.e., its length excluding the terminating null character). * L is treated as operator "" X(str, len) */ CPPPointerType strType = new CPPPointerType(new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null), true, false, false); IASTInitializerClause[] initializer = new IASTInitializerClause[] { createArgForType(exp, strType), createArgForType(null, CPPBasicType.UNSIGNED_INT) }; data.setFunctionArguments(false, initializer); ret = resolveFunction(data, funcs, true); } else if (kind == IASTLiteralExpression.lk_char_constant) { /* * 2.14.8.6 * If L is a user-defined-character-literal, let ch be the literal * without its ud-suffix. S shall contain a literal operator whose * only parameter has the type ch and the literal L is treated as a * call operator "" X(ch) */ CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp); data.setFunctionArguments(false, createArgForType(exp, t)); ret = resolveFunction(data, funcs, true); } return ret; } static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set, IASTNode point) { targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR); if (!(targetType instanceof ICPPFunctionType)) return null; // First pass, consider functions ICPPFunction[] fns= set.getBindings(); 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= point.getTranslationUnit(); for (IFunction fn : fns) { try { if (fn instanceof ICPPFunctionTemplate) { final ICPPFunctionTemplate template = (ICPPFunctionTemplate) fn; ICPPFunction inst= CPPTemplates.instantiateForAddressOfFunction(template, (ICPPFunctionType) targetType, set.getTemplateArguments(), point); if (inst != null) { int cmp= CPPTemplates.orderFunctionTemplates(resultTemplate, template, TypeSelection.PARAMETERS_AND_RETURN_TYPE, point); 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 findOverloadedBinaryOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, OverloadableOperator op, ICPPEvaluation arg1, ICPPEvaluation arg2) { if (op == null || arg1 == null || arg2 == null) return null; IType op1type = getNestedType(arg1.getType(pointOfInstantiation), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined( getNestedType(arg2.getType(pointOfInstantiation), TDEF | REF | CVTYPE))) return null; final LookupMode lookupNonMember; if (op == OverloadableOperator.ASSIGN || op == OverloadableOperator.BRACKET) { lookupNonMember = LookupMode.NO_GLOBALS; } else { lookupNonMember= LookupMode.LIMITED_GLOBALS; } return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, new ICPPEvaluation[] {arg1, arg2}, op1type, op, lookupNonMember); } public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression expr) { OverloadableOperator op = OverloadableOperator.fromNewExpression(expr); final ICPPEvaluation evaluation = ((ICPPEvaluationOwner) expr).getEvaluation(); if (evaluation.isTypeDependent()) return null; final IASTInitializerClause[] placement = expr.getPlacementArguments(); final ICPPEvaluation arg1= new EvalUnary(IASTUnaryExpression.op_star, evaluation, null, expr); final ICPPEvaluation arg2= new EvalUnary(IASTUnaryExpression.op_sizeof, evaluation, null, expr); ICPPEvaluation[] args; if (placement == null) { args= new ICPPEvaluation[] { arg1, arg2 }; } else { args= new ICPPEvaluation[2 + placement.length]; args[0]= arg1; args[1]= arg2; int i= 2; for (IASTInitializerClause p : placement) { final ICPPEvaluationOwner arg = (ICPPEvaluationOwner) p; final ICPPEvaluation a = arg.getEvaluation(); if (a.isTypeDependent()) return null; args[i++]= a; } } IType type= getNestedType(arg1.getType(expr), TDEF | REF | CVTYPE); return findOverloadedOperator(expr, null, args, 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; ICPPEvaluation[] args = { new EvalFixed(type, LVALUE, IntegralValue.UNKNOWN), ((ICPPEvaluationOwner) expr.getOperand()).getEvaluation() }; return findOverloadedOperator(expr, null, 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} if no constructor is called. */ public static IBinding 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} if no constructor is called. Returns a {@link IProblemBinding} if the called * constructor cannot be uniquely resolved. */ public static IBinding 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} if no constructor is called. */ private static IBinding findImplicitlyCalledConstructor(IASTName name, IASTInitializer initializer) { IBinding binding = name.resolveBinding(); if (!(binding instanceof ICPPVariable)) return null; IType type = ((ICPPVariable) binding).getType(); type = SemanticUtil.getNestedType(type, TDEF | CVTYPE); if (!(type instanceof ICPPClassType)) return null; if (type instanceof ICPPClassTemplate || type instanceof ICPPUnknownType || type instanceof ISemanticProblem) return null; return findImplicitlyCalledConstructor((ICPPClassType) type, initializer, name); } /** * Returns the constructor implicitly called by the given expression, or {@code null} if there is no * constructor call, or a {@link IProblemBinding} if the called constructor cannot be uniquely resolved. */ public static IBinding findImplicitlyCalledConstructor(ICPPASTNewExpression expr) { IType type = getNestedType(expr.getExpressionType(), TDEF | REF | CVTYPE); if (!(type instanceof IPointerType)) return null; type = ((IPointerType) type).getType(); if (type instanceof ICPPClassType) { return findImplicitlyCalledConstructor((ICPPClassType) type, expr.getInitializer(), expr.getTypeId()); } return null; } private static IBinding findImplicitlyCalledConstructor(ICPPClassType type, IASTInitializer initializer, IASTNode typeId) { try { if (initializer instanceof IASTEqualsInitializer) { // Copy initialization. IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer; ICPPEvaluationOwner evalOwner = (ICPPEvaluationOwner) eqInit.getInitializerClause(); final ICPPEvaluation evaluation = evalOwner.getEvaluation(); IType sourceType= evaluation.getType(typeId); ValueCategory isLValue= evaluation.getValueCategory(typeId); if (sourceType != null) { Cost c; if (calculateInheritanceDepth(sourceType, type, typeId) >= 0) { c = Conversions.copyInitializationOfClass(isLValue, sourceType, type, false, typeId); } else { c = Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED, Context.ORDINARY, typeId); } if (c.converts()) { ICPPFunction f = c.getUserDefinedConversion(); if (f instanceof ICPPConstructor) return f; // If a conversion is used, the constructor is elided. } } } else if (initializer instanceof ICPPASTInitializerList) { // List initialization. ICPPEvaluation eval= ((ICPPEvaluationOwner) initializer).getEvaluation(); if (eval instanceof EvalInitList) { Cost c= Conversions.listInitializationSequence((EvalInitList) eval, type, UDCMode.ALLOWED, true, typeId); if (c.converts()) { ICPPFunction f = c.getUserDefinedConversion(); if (f instanceof ICPPConstructor) return f; } } } else if (initializer instanceof ICPPASTConstructorInitializer) { // Direct initialization. return findImplicitlyCalledConstructor(type, (ICPPASTConstructorInitializer) initializer, typeId); } else if (initializer == null) { // Default initialization. ICPPConstructor[] ctors = ClassTypeHelper.getConstructors(type, typeId); for (ICPPConstructor ctor : ctors) { if (ctor.getRequiredArgumentCount() == 0) return ctor; } return null; } } catch (DOMException e) { } return null; } private static IBinding findImplicitlyCalledConstructor(ICPPClassType classType, ICPPASTConstructorInitializer initializer, IASTNode typeId) { final IASTInitializerClause[] arguments = initializer.getArguments(); CPPASTName astName = new CPPASTName(); astName.setName(classType.getNameCharArray()); astName.setOffsetAndLength((ASTNode) typeId); CPPASTIdExpression idExp = new CPPASTIdExpression(astName); idExp.setParent(typeId.getParent()); idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); LookupData data = new LookupData(astName); data.setFunctionArguments(false, arguments); data.qualified = true; data.foundItems = ClassTypeHelper.getConstructors(classType, typeId); try { return resolveAmbiguities(data); } 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; final char[] name = CharArrayUtils.concat("~".toCharArray(), cls.getNameCharArray()); //$NON-NLS-1$ LookupData data = new LookupData(name, null, expr); data.qualified = true; data.setFunctionArguments(true, new EvalFixed(cls, LVALUE, IntegralValue.UNKNOWN)); try { lookup(data, scope); IBinding[] found= data.getFoundBindings(); if (found.length > 0 && found[0] instanceof ICPPFunction) { return (ICPPFunction) found[0]; } } catch (DOMException e) { } return null; } public static ICPPASTExpression 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; } /** * For simplicity returns an operator of form RT (T, T) rather than RT (boolean, T, T) */ public static ICPPFunction findOverloadedConditionalOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, ICPPEvaluation positive, ICPPEvaluation negative) { final ICPPEvaluation[] args = new ICPPEvaluation[] {positive, negative}; return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, 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(IASTNode pointOfInstantiation, IScope pointOfDefinition, ICPPEvaluation arg1, ICPPEvaluation arg2) { IType op1type = getNestedType(arg1.getType(pointOfInstantiation), TDEF | REF | CVTYPE); IType op2type = getNestedType(arg2.getType(pointOfInstantiation), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined(op2type)) return null; ICPPEvaluation[] args = { arg1 , arg2 }; return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, args, op1type, OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS); } static enum LookupMode {NO_GLOBALS, GLOBALS_IF_NO_MEMBERS, LIMITED_GLOBALS, ALL_GLOBALS} static ICPPFunction findOverloadedOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, ICPPEvaluation[] args, IType methodLookupType, OverloadableOperator operator, LookupMode mode) { while (pointOfInstantiation instanceof IASTName) { pointOfInstantiation= pointOfInstantiation.getParent(); } ICPPClassType callToObjectOfClassType= null; IType type2= null; if (args.length >= 2) { type2 = args[1].getType(pointOfInstantiation); type2= getNestedType(type2, TDEF | REF | CVTYPE); } // Find a method LookupData methodData = null; if (methodLookupType instanceof ISemanticProblem) return null; if (methodLookupType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) methodLookupType; methodData = new LookupData(operator.toCharArray(), null, pointOfInstantiation); methodData.setFunctionArguments(true, args); methodData.qualified = true; // (13.3.1.2.3) try { IScope scope = classType.getCompositeScope(); if (scope == null) return null; lookup(methodData, scope); if (operator == OverloadableOperator.PAREN) { callToObjectOfClassType= classType; } } catch (DOMException e) { return null; } } // Find a function LookupData funcData = new LookupData(operator.toCharArray(), null, pointOfInstantiation); // 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(pointOfInstantiation); if (scope == null) return null; lookup(funcData, scope); try { doKoenigLookup(funcData); } catch (DOMException e) { } // Also do a lookup at the point of definition. if (pointOfDefinition != null) { LookupData funcData2 = new LookupData(operator.toCharArray(), null, pointOfInstantiation); funcData2.setFunctionArguments(true, args); funcData2.ignoreMembers = true; lookup(funcData2, pointOfDefinition); if (funcData2.hasResults()) { mergeResults(funcData, funcData2.foundItems, false); } } // Filter with file-set IASTTranslationUnit tu= pointOfInstantiation.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, pointOfInstantiation); 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(pointOfInstantiation.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, pointOfInstantiation, (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); } else if (funcData.hasResults()) { binding = resolveAmbiguities(funcData); } else if (methodData != null) { binding = resolveAmbiguities(methodData); } 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, false); } static boolean isUserDefined(IType type) { if (type instanceof ISemanticProblem) return false; return type instanceof ICPPClassType || type instanceof IEnumeration || type instanceof ICPPUnknownType; } public static IBinding[] findBindingsInScope(IScope scope, String name, IASTTranslationUnit tu) { LookupData data = new LookupData(name.toCharArray(), null, tu); return standardLookup(data, scope); } 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) { LookupData data; if (beforeNode == null) { data= new LookupData(name, null, ASTInternal.getPhysicalNodeOfScope(scope)); data.setIgnorePointOfDeclaration(true); } else { data= new LookupData(name, null, beforeNode); data.setIgnorePointOfDeclaration(false); } data.qualified = qualified; return standardLookup(data, scope); } public static IBinding[] findBindingsForContentAssist(IASTName name, boolean prefixLookup, String[] additionalNamespaces) { LookupData data = createLookupData(name); data.contentAssist = true; data.fHeuristicBaseLookup = true; data.setPrefixLookup(prefixLookup); data.foundItems = new CharArrayObjectMap<>(2); // Convert namespaces to scopes. List<ICPPScope> nsScopes= new ArrayList<>(); IASTTranslationUnit tu = name.getTranslationUnit(); if (additionalNamespaces != null && tu instanceof CPPASTTranslationUnit) { 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((CPPASTTranslationUnit) tu, namespaceParts, name); if (nsScope != null) { nsScopes.add(nsScope); } } catch (DOMException e) { // Errors in source code, continue with next candidate. } } } return contentAssistLookup(data, nsScopes); } private static IScope getLookupScope(IASTNode node) { if (node == null) return null; if (node instanceof IASTCompositeTypeSpecifier) return ((IASTCompositeTypeSpecifier) node).getScope(); if (node instanceof ICPPASTNamespaceDefinition) return ((ICPPASTNamespaceDefinition) node).getScope(); if (!(node instanceof ICPPInternalBinding)) return null; IASTNode defn = ((ICPPInternalBinding) node).getDefinition(); if (defn == null) return null; return getLookupScope(defn.getParent()); } private static IScope getLookupScope(IBinding binding) { if (binding == null) return null; if (binding instanceof IASTCompositeTypeSpecifier) return ((IASTCompositeTypeSpecifier) binding).getScope(); if (!(binding instanceof ICPPInternalBinding)) return null; IASTNode defn = ((ICPPInternalBinding) binding).getDefinition(); if (defn == null) return null; return getLookupScope(defn.getParent()); } /** * Uses C++ lookup semantics to find the possible bindings for the given qualified name starting * in the given scope. */ public static IBinding[] findBindingsForQualifiedName(IScope scope, String qualifiedName) { // Return immediately if the qualifiedName does not match a known format. Matcher m = QUALNAME_REGEX.matcher(qualifiedName); if (!m.matches()) return IBinding.EMPTY_BINDING_ARRAY; // If the qualified name is rooted in the global namespace, then navigate to that scope. boolean isGlobal = m.group(1) != null; if (isGlobal) { IScope global = scope; try { while (global.getParent() != null) { global = global.getParent(); } } catch (DOMException e) { CCorePlugin.log(e); } scope = global; } Set<IBinding> bindings = new HashSet<>(); // Look for the name in the given scope. findBindingsForQualifiedName(scope, qualifiedName, bindings); // If the qualified name is not rooted in the global namespace (with a leading ::), then // look at all parent scopes. if (!isGlobal) { try { while (scope != null) { scope = scope.getParent(); if (scope != null) findBindingsForQualifiedName(scope, qualifiedName, bindings); } } catch (DOMException e) { CCorePlugin.log(e); } } return bindings.size() == 0 ? IBinding.EMPTY_BINDING_ARRAY : bindings.toArray(new IBinding[bindings.size()]); } private static void findBindingsForQualifiedName(IScope scope, String qualifiedName, Collection<IBinding> bindings) { // Split the qualified name into the first part (before the first :: qualifier) and the rest. All // bindings for the first part are found and their scope is used to find the rest of the name. When // the call tree gets to a leaf (non-qualified name) then a simple lookup happens and all matching // bindings are added to the result. Matcher m = QUALNAME_REGEX.matcher(qualifiedName); if (!m.matches()) return; String part1 = m.group(2); String part2 = m.group(3); // When we're down to a single component name, then use the normal lookup method. if (part2 == null || part2.isEmpty()) { bindings.addAll(Arrays.asList(findBindings(scope, part1, false))); return; } // Find all bindings that match the first part of the name. For each such binding, // lookup the second part of the name. for (IBinding binding : findBindings(scope, part1, false)) { findBindingsForQualifiedName(getLookupScope(binding), part2, bindings); } } private static ICPPScope getNamespaceScope(CPPASTTranslationUnit tu, String[] namespaceParts, IASTNode point) throws DOMException { ICPPScope nsScope= tu.getScope(); outer: for (String nsPart : namespaceParts) { nsPart= nsPart.trim(); if (nsPart.length() != 0) { IBinding[] nsBindings = nsScope.getBindings(new ScopeLookupData(nsPart.toCharArray(), point)); 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.qualified = true; for (ICPPScope nsScope : additionalNamespaces) { if (!data.visited.containsKey(nsScope)) { lookup(data, nsScope); } } } } catch (DOMException e) { } @SuppressWarnings("unchecked") CharArrayObjectMap<Object> map = (CharArrayObjectMap<Object>) 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 IBinding.EMPTY_BINDING_ARRAY; ObjectSet<IBinding> set = new ObjectSet<>(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; } 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; } protected static IBinding resolveUnknownName(IScope scope, ICPPUnknownBinding unknown, IASTNode point) { final char[] unknownName = unknown.getNameCharArray(); LookupData data = new LookupData(unknownName, null, point); data.setIgnorePointOfDeclaration(true); data.typesOnly= unknown instanceof IType; data.qualified= true; 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); } 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(new CPPASTName(unknownName), point, IProblemBinding.SEMANTIC_NAME_NOT_FOUND); return binding; } }