blob: 28da07be9de8b934b1873769a513afa588f192fa [file] [log] [blame]
/*******************************************************************************
* 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.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
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.ICPPASTCapture;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
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.ICPPASTInitCapture;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.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.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
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.ICPPAliasTemplate;
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.ICPPFunctionSpecialization;
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.ITypeContainer;
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.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.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.cdt.internal.core.pdom.dom.IPDOMAdaptedASTNode;
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);
// 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$
// This flag controls whether name lookup is allowed to find bindings in headers
// that are not reachable via includes from the file containing the name.
// Generally this is not allowed, but certain consumers, such as IncludeOrganizer,
// need it (since the whole point of IncludeOrganizer is to find missing headers).
private static final ThreadLocal<Boolean> fAllowPromiscuousBindingResolution = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
private static final ThreadLocal<Deque<IASTNode>> fLookupPoints = new ThreadLocal<Deque<IASTNode>>() {
@Override
protected Deque<IASTNode> initialValue() {
return new ArrayDeque<>();
}
};
public static void pushLookupPoint(IASTNode point) {
fLookupPoints.get().push(point);
}
public static void popLookupPoint() {
fLookupPoints.get().pop();
}
/**
* Get the current point of instantiation / point of lookup for name lookups.
*
* NOTE: This is meant to be used primarily for "declaredBefore" purposes, that is,
* for determining whether something was declared before or after the point
* of lookup. It is NOT meant to be used as a general mechanism for accessing
* information about a call site without having to pass that information along
* the usual way (via function arguments).
*/
public static IASTNode getCurrentLookupPoint() {
Deque<IASTNode> lookupPoints = fLookupPoints.get();
return lookupPoints.isEmpty() ? null : lookupPoints.peek();
}
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);
IBinding binding;
pushLookupPoint(name);
try {
try {
// 2: Lookup
lookup(data, null);
// Perform argument dependent lookup
if (data.checkAssociatedScopes() && !data.hasTypeOrMemberFunctionOrVariableResult()) {
doArgumentDependentLookup(data);
}
} catch (DOMException e) {
data.problem = (ProblemBinding) e.getProblem();
}
if (data.problem != null)
return data.problem;
// 3: Resolve ambiguities
try {
binding = resolveAmbiguities(data);
} catch (DOMException e) {
binding = e.getProblem();
}
// 4: Post processing
binding = postResolution(binding, data);
} finally {
popLookupPoint();
}
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 != 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);
}
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);
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, cls.getConstructors(), true, false);
}
} 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();
}
boolean isNestedNameSpecifier = false;
if (nameParent instanceof ICPPASTQualifiedName) {
if (name == ((ICPPASTQualifiedName) nameParent).getLastName()) {
name= (IASTName) nameParent;
nameParent= name.getParent();
} else {
isNestedNameSpecifier = true;
}
}
// 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 (isNestedNameSpecifier || 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);
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 doArgumentDependentLookup(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;
data.setArgumentDependent(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;
data.setArgumentDependent(false);
}
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 = ct.getBases();
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 : ct.getFriends()) {
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);
ICPPTemplateArgument[] templateArgs = data.getTemplateArguments();
LookupData ld2= new LookupData(tchars, templateArgs, 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();
ITypedef typedef = null;
for (IBinding candidate : typedefs) {
if (!(candidate instanceof IType)) {
continue;
}
IType type = (IType) candidate;
if (templateArgs != null && type instanceof ICPPAliasTemplate) {
IBinding instantiated = CPPTemplates.instantiateAliasTemplate((ICPPAliasTemplate) type,
templateArgs);
if (instantiated instanceof IType) {
type = (IType) instantiated;
}
}
if (type instanceof ITypedef) {
typedef = (ITypedef) type;
break;
}
}
if (typedef == null) {
return false;
}
IType t= SemanticUtil.getNestedType(typedef, 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(litExpr.getEvaluation().getType(), 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());
}
if (data.namespacesOnly) {
bindings = ArrayUtil.filter(bindings, (argument) -> {
return argument instanceof ICPPNamespace;
});
}
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) {
ICPPASTLambdaExpression lambdaExpression = (ICPPASTLambdaExpression) p;
for (ICPPASTCapture capture : lambdaExpression.getCaptures()) {
if (capture instanceof ICPPASTInitCapture) {
IASTName name = capture.getIdentifier();
if (name != null) {
ASTInternal.addName(scope, name);
}
}
}
ICPPASTFunctionDeclarator lambdaDeclarator = lambdaExpression.getDeclarator();
if (lambdaDeclarator != null) {
nodes = lambdaDeclarator.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) {
ICPPASTSwitchStatement ifStatement = (ICPPASTSwitchStatement) parent;
final IASTStatement initStatement = ifStatement.getInitializerStatement();
final IASTDeclaration controllerDeclaration = ifStatement.getControllerDeclaration();
if (initStatement != null) {
nodes = new IASTNode[] {initStatement, controllerDeclaration};
} else {
nodes = new IASTNode[] {controllerDeclaration};
}
} else if (parent instanceof ICPPASTIfStatement) {
ICPPASTIfStatement ifStatement = (ICPPASTIfStatement) parent;
final IASTStatement initStatement = ifStatement.getInitializerStatement();
final IASTDeclaration conditionDeclaration = ifStatement.getConditionDeclaration();
if (initStatement != null) {
nodes = new IASTNode[] {initStatement, conditionDeclaration};
} else {
nodes = new IASTNode[] {conditionDeclaration};
}
} 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;
boolean isInline = nsDef.isInline();
// An inline namespace can be re-opened without repeating the inline keyword,
// so we need to consult the binding to check inlineness.
if (!isUnnamed && !isInline) {
IBinding nsBinding = nsDef.getName().resolveBinding();
if (nsBinding instanceof ICPPNamespace) {
isInline = ((ICPPNamespace) nsBinding).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 instanceof IPDOMAdaptedASTNode) {
// Get the underlying ASTNode.
node = ((IPDOMAdaptedASTNode) node).getDelegate();
}
if (!(node instanceof ASTNode))
return true;
// The pointOfRef and pointOfDecl variables contain node offsets scaled by a factor of two.
// This is done to distinguish between left and right points for the same offset.
final int pointOfRef= ((ASTNode) node).getOffset() * 2;
ASTNode nd = null;
while (obj instanceof ICPPSpecialization) {
obj = ((ICPPSpecialization) obj).getSpecializedBinding();
}
int pointOfDecl= -1;
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() * 2;
}
}
if (pointOfDecl < 0) {
if (nd != null) {
pointOfDecl = getPointOfDeclaration(nd);
} else if (obj instanceof IIndexBinding && !isUsingPromiscuousBindingResolution()) {
IIndexBinding indexBinding = (IIndexBinding) obj;
if (indexBinding instanceof ICPPMethod && ((ICPPMethod) indexBinding).isImplicit()) {
return true;
}
IASTTranslationUnit tu = node.getTranslationUnit();
IIndexFileSet indexFileSet = tu.getIndexFileSet();
return (indexFileSet != null && indexFileSet.containsDeclaration(indexBinding));
}
}
return pointOfDecl < pointOfRef;
}
/**
* Returns the point of declaration for the given AST node. The point of declaration is a node offset
* scaled by a factor of two. This is done to distinguish between left and right points for the offset.
*/
private static int getPointOfDeclaration(ASTNode nd) {
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) {
return ((ASTNode) init).getOffset() * 2 - 1;
} else {
return (((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength()) * 2 - 1;
}
} 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();
return (exp.getOffset() + exp.getLength()) * 2 - 1;
} else {
return (nd.getOffset() + nd.getLength()) * 2 - 1;
}
} else if (prop == ICPPASTUsingDeclaration.NAME) {
nd = (ASTNode) nd.getParent();
return nd.getOffset() * 2;
} else if (prop == ICPPASTNamespaceAlias.ALIAS_NAME) {
nd = (ASTNode) nd.getParent();
return (nd.getOffset() + nd.getLength()) * 2 - 1;
} 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();
return (targetType.getOffset() + targetType.getLength()) * 2 - 1;
} 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();
return (nd.getOffset() + nd.getLength()) * 2 - 1;
} else {
return (nd.getOffset() + nd.getLength()) * 2 - 1;
}
}
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, false);
}
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 {@link IIndexBinding} and not
* a specialization of an IIndexBinding.
*
* @param ast the ast to check
* @param binding the binding to check
* @return {@code true} if the {@code binding}> is reachable from the {@code ast}
*/
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 name is an AST name, or is reachable from the AST through includes.
* The name is assumed to belong to the AST, if it is not an {@link IIndexName}.
*
* @param ast the ast to check
* @param name the name to check
* @return {@code true} if the {@code name}> is reachable from the {@code ast}
*/
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,
boolean resolveTargetedArgumentTypes) 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(), 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);
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)) {
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;
FunctionCost fnCost= costForFunctionCall(fn, udc, data, resolveTargetedArgumentTypes);
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()) {
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;
}
/**
* If {@code type} is a {@link FunctionSetType} or a pointer type containing a FunctionSetType,
* resolves the FunctionSetType using the given target type.
*
* @param type the type to resolve
* @param targetType the target type
* @param point the name lookup context
* @return the resolved type, or the given {@type} if the type didn't contain a FunctionSetType
* or the targeted function resolution failed
*/
private static IType resolveTargetedFunctionSetType(IType type, IType targetType) {
IType t = type;
if (type instanceof IPointerType) {
t = ((IPointerType) type).getType();
}
if (t instanceof FunctionSetType) {
ICPPFunction function =
resolveTargetedFunction(targetType, ((FunctionSetType) t).getFunctionSet());
if (function != null && !(function instanceof IProblemBinding)) {
type = function.getType();
if (targetType instanceof ITypeContainer) {
ITypeContainer containerType = (ITypeContainer) targetType.clone();
containerType.setType(type);
type = containerType;
}
}
}
return type;
}
private static IBinding createFunctionSet(ICPPFunction[] fns, ICPPTemplateArgument[] args, 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);
return f == null ? new CPPFunctionSet(fns, args, name) : f;
}
private static ICPPFunction getUniqueFunctionForSet(ICPPFunction[] fns, ICPPTemplateArgument[] args) {
// 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)) {
isCandidate= false;
} else {
f = CPPTemplates.instantiateForAddressOfFunction(funcTemp, null, args);
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);
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);
if (inst != null) {
int cmp= CPPTemplates.orderFunctionTemplates(bestTemplate, template, TypeSelection.PARAMETERS_AND_RETURN_TYPE);
if (cmp == 0)
cmp= compareByRelevance(tu, bestTemplate, template);
if (cmp == 0)
isAmbiguous= true;
if (cmp < 0) {
isAmbiguous= false;
bestTemplate= template;
bestInst= inst;
}
}
}
}
if (isAmbiguous)
return new ProblemBinding(data.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,
boolean resolveTargetedArgumentTypes) throws DOMException {
final ICPPFunctionType ftype= fn.getType();
if (ftype == null)
return null;
IType[] argTypes= data.getFunctionArgumentTypes();
ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories();
if (resolveTargetedArgumentTypes) {
IType[] newArgTypes = null;
IType[] paramTypes = fn.getType().getParameterTypes();
for (int i = 0; i < argTypes.length && i < paramTypes.length; i++) {
IType argType = argTypes[i];
IType paramType = paramTypes[i];
IType newArgType = resolveTargetedFunctionSetType(argType, paramType);
if (newArgType != argType) {
if (newArgTypes == null) {
newArgTypes = new IType[argTypes.length];
System.arraycopy(argTypes, 0, newArgTypes, 0, argTypes.length);
}
newArgTypes[i] = newArgType;
}
}
if (newArgTypes != null) {
argTypes = newArgTypes;
}
}
int skipArg= 0;
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);
} else {
result= new FunctionCost(fn, sourceLen + 1);
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);
if (cost.converts()) {
cost.setImpliedObject();
} else {
if (CPPTemplates.isDependentType(implicitParameterType) || CPPTemplates.isDependentType(impliedObjectType)) {
IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE);
IType t= getNestedType(implicitParameterType, TDEF|REF|CVTYPE);
if (SemanticUtil.calculateInheritanceDepth(s, t) >= 0)
return null;
return CONTAINS_DEPENDENT_TYPES;
}
}
}
if (!cost.converts())
return null;
result.setCost(k++, cost, 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);
} 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);
if (data.fNoNarrowing && cost.isNarrowingConversion()) {
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);
}
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) {
pushLookupPoint(name);
try {
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,
((ICPPClassType) targetType).getConstructors(), true, false);
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 (((ICPPASTExpression) parent).getEvaluation().isTypeDependent()) {
return CPPDeferredFunction.createForCandidates(functionSet.getBindings());
}
}
ICPPFunction function = resolveTargetedFunction(targetType, functionSet);
if (function == null)
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_OVERLOAD);
return function;
} finally {
popLookupPoint();
}
}
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 SemanticUtil.getNestedType(func.getParameters()[0].getType(), CVTYPE).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 {
pushLookupPoint(exp);
IBinding ret = null;
try {
/*
* 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();
IScope lookupScope = CPPVisitor.getContainingScope(exp);
IBinding[] bindings = findBindings(lookupScope, ((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, false);
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, false);
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, false);
//
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])));
}
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp);
IBinding litTpl = resolveFunction(data, tplFunctions, true, false);
// 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, false);
} 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, false);
}
} finally {
popLookupPoint();
}
return ret;
}
/**
* 13.4-1 A use of an overloaded function without arguments is resolved in certain contexts to
* a function.
*/
static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set) {
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= CPPSemantics.getCurrentLookupPoint().getTranslationUnit();
for (IFunction fn : fns) {
try {
if (fn instanceof ICPPFunctionTemplate) {
final ICPPFunctionTemplate template = (ICPPFunctionTemplate) fn;
ICPPFunction inst= CPPTemplates.instantiateForAddressOfFunction(template,
(ICPPFunctionType) targetType, set.getTemplateArguments());
if (inst != null) {
int cmp= CPPTemplates.orderFunctionTemplates(resultTemplate, template,
TypeSelection.PARAMETERS_AND_RETURN_TYPE);
if (cmp == 0)
cmp= compareByRelevance(tu, resultTemplate, template);
if (cmp == 0)
isAmbiguous= true;
if (cmp < 0) {
isAmbiguous= false;
resultTemplate= template;
result= inst;
}
}
}
} catch (DOMException e) {
}
}
if (isAmbiguous)
return null;
return result;
}
public static ICPPFunction findOverloadedBinaryOperator(IScope pointOfDefinition,
OverloadableOperator op, ICPPEvaluation arg1, ICPPEvaluation arg2) {
if (op == null || arg1 == null || arg2 == null)
return null;
IType op1type = getNestedType(arg1.getType(), TDEF | REF | CVTYPE);
if (!isUserDefined(op1type) && !isUserDefined(
getNestedType(arg2.getType(), 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(pointOfDefinition, new ICPPEvaluation[] {arg1, arg2}, op1type, op,
lookupNonMember);
}
public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression expr) {
pushLookupPoint(expr);
try {
OverloadableOperator op = OverloadableOperator.fromNewExpression(expr);
final ICPPEvaluation evaluation = 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 ICPPEvaluation a = ((ICPPASTInitializerClause) p).getEvaluation();
if (a.isTypeDependent())
return null;
args[i++]= a;
}
}
IType type= getNestedType(arg1.getType(), TDEF | REF | CVTYPE);
return findOverloadedOperator(null, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS);
} finally {
popLookupPoint();
}
}
public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression expr) {
pushLookupPoint(expr);
try {
OverloadableOperator op = OverloadableOperator.fromDeleteExpression(expr);
IType type = getTypeOfPointer(expr.getOperand().getExpressionType());
if (type == null)
return null;
ICPPEvaluation[] args = {
new EvalFixed(type, LVALUE, IntegralValue.UNKNOWN),
((ICPPASTExpression) expr.getOperand()).getEvaluation()
};
return findOverloadedOperator(null, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS);
} finally {
popLookupPoint();
}
}
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) {
pushLookupPoint(declarator);
try {
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);
}
} finally {
popLookupPoint();
}
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;
// The class type may be declared in a header but defined in the AST.
// In such a case, we want the constructors as AST bindings (since as
// index bindings they would fail declaredBefore() filtering), so map
// the class type to its AST representation.
type = SemanticUtil.mapToAST(type);
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) {
pushLookupPoint(typeId);
try {
if (initializer instanceof IASTEqualsInitializer) {
// Copy initialization.
IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer;
ICPPASTInitializerClause evalOwner = (ICPPASTInitializerClause) eqInit.getInitializerClause();
final ICPPEvaluation evaluation = evalOwner.getEvaluation();
IType sourceType= evaluation.getType();
ValueCategory isLValue= evaluation.getValueCategory();
if (sourceType != null) {
Cost c;
if (calculateInheritanceDepth(sourceType, type) >= 0) {
c = Conversions.copyInitializationOfClass(isLValue, sourceType, type, false);
} else {
c = Conversions.checkImplicitConversionSequence(type, sourceType, isLValue,
UDCMode.ALLOWED, Context.ORDINARY);
}
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= ((ICPPASTInitializerClause) initializer).getEvaluation();
if (eval instanceof EvalInitList) {
Cost c= Conversions.listInitializationSequence((EvalInitList) eval, type, UDCMode.ALLOWED, true);
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 = type.getConstructors();
for (ICPPConstructor ctor : ctors) {
if (ctor.getRequiredArgumentCount() == 0)
return ctor;
}
return null;
}
} catch (DOMException e) {
} finally {
popLookupPoint();
}
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 = classType.getConstructors();
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(IScope pointOfDefinition,
ICPPEvaluation positive, ICPPEvaluation negative) {
final ICPPEvaluation[] args = new ICPPEvaluation[] {positive, negative};
return findOverloadedOperator(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(IScope pointOfDefinition,
ICPPEvaluation arg1, ICPPEvaluation arg2) {
IType op1type = getNestedType(arg1.getType(), TDEF | REF | CVTYPE);
IType op2type = getNestedType(arg2.getType(), TDEF | REF | CVTYPE);
if (!isUserDefined(op1type) && !isUserDefined(op2type))
return null;
ICPPEvaluation[] args = { arg1 , arg2 };
return findOverloadedOperator(pointOfDefinition, args, op1type,
OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS);
}
static enum LookupMode {NO_GLOBALS, GLOBALS_IF_NO_MEMBERS, LIMITED_GLOBALS, ALL_GLOBALS}
static LookupData findOverloadedMemberOperator(IType methodLookupType, OverloadableOperator operator,
ICPPEvaluation[] args, IASTNode pointOfInstantiation) {
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);
} catch (DOMException e) {
return null;
}
}
return methodData;
}
static LookupData findOverloadedNonmemberOperator(IType methodLookupType, OverloadableOperator operator,
ICPPEvaluation[] args, IASTNode pointOfInstantiation, IScope pointOfDefinition,
LookupData methodData, LookupMode mode, IType type2, ICPPClassType callToObjectOfClassType) {
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 funcData;
lookup(funcData, scope);
try {
doArgumentDependentLookup(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 (!indexBindingIsReachable(fileSet, (IIndexBinding) item)) {
continue;
}
}
items[j++]= item;
}
}
}
} catch (DOMException e) {
return funcData;
}
if (operator == OverloadableOperator.NEW || operator == OverloadableOperator.DELETE
|| operator == OverloadableOperator.NEW_ARRAY || operator == OverloadableOperator.DELETE_ARRAY) {
// Those operators replace the built-in operator
Object[] items= (Object[]) funcData.foundItems;
int j= 0;
for (Object object : items) {
if (object instanceof ICPPFunction) {
ICPPFunction func= (ICPPFunction) object;
if (!(func instanceof CPPImplicitFunction))
items[j++]= func;
}
}
if (j > 0) {
while (j < items.length) {
items[j++]= null;
}
}
}
// 13.3.1.2.3
// However, if no operand type has class type, only those non-member functions ...
if (mode == LookupMode.LIMITED_GLOBALS) {
if (funcData.foundItems != null && !(methodLookupType instanceof ICPPClassType) && !(type2 instanceof ICPPClassType)) {
IEnumeration enum1= null;
IEnumeration enum2= null;
if (methodLookupType instanceof IEnumeration) {
enum1= (IEnumeration) methodLookupType;
}
if (type2 instanceof IEnumeration) {
enum2= (IEnumeration) type2;
}
Object[] items= (Object[]) funcData.foundItems;
int j= 0;
for (Object object : items) {
if (object instanceof ICPPFunction) {
ICPPFunction func= (ICPPFunction) object;
ICPPFunctionType ft = func.getType();
IType[] pts= ft.getParameterTypes();
if ((enum1 != null && pts.length > 0 && enum1.isSameType(getUltimateTypeUptoPointers(pts[0]))) ||
(enum2 != null && pts.length > 1 && enum2.isSameType(getUltimateTypeUptoPointers(pts[1])))) {
items[j++]= object;
}
}
}
while (j < items.length) {
items[j++]= null;
}
}
}
}
if (callToObjectOfClassType != null) {
try {
// 13.3.1.1.2 call to object of class type
ICPPMethod[] ops = SemanticUtil.getConversionOperators(callToObjectOfClassType);
for (ICPPMethod op : ops) {
if (op.isExplicit())
continue;
IFunctionType ft= op.getType();
if (ft != null) {
IType rt= SemanticUtil.getNestedType(ft.getReturnType(), SemanticUtil.TDEF);
if (rt instanceof IPointerType) {
IType ptt= SemanticUtil.getNestedType(((IPointerType) rt).getType(), SemanticUtil.TDEF);
if (ptt instanceof IFunctionType) {
IFunctionType ft2= (IFunctionType) ptt;
IBinding sf= createSurrogateCallFunction(pointOfInstantiation.getTranslationUnit().getScope(), ft2.getReturnType(), rt, ft2.getParameterTypes());
mergeResults(funcData, sf, false);
}
}
}
}
} catch (DOMException e) {
return funcData;
}
}
if (methodLookupType instanceof ICPPClassType || type2 instanceof ICPPClassType) {
ICPPFunction[] builtins= BuiltinOperators.create(operator, args, (Object[]) funcData.foundItems);
mergeResults(funcData, builtins, false);
}
return funcData;
}
static ICPPFunction findOverloadedOperator(IScope pointOfDefinition, ICPPEvaluation[] args,
IType methodLookupType, OverloadableOperator operator, LookupMode mode) {
IASTNode pointOfInstantiation = CPPSemantics.getCurrentLookupPoint();
while (pointOfInstantiation instanceof IASTName) {
pointOfInstantiation= pointOfInstantiation.getParent();
}
ICPPClassType callToObjectOfClassType= null;
IType type2= null;
if (args.length >= 2) {
type2 = args[1].getType();
type2= getNestedType(type2, TDEF | REF | CVTYPE);
}
// Find a method
LookupData methodData = findOverloadedMemberOperator(methodLookupType, operator, args,
pointOfInstantiation);
if (methodData != null && operator == OverloadableOperator.PAREN) {
callToObjectOfClassType = (ICPPClassType) methodLookupType;
}
// Find a function
LookupData funcData = findOverloadedNonmemberOperator(methodLookupType, operator, args,
pointOfInstantiation, pointOfDefinition, methodData, mode, type2, callToObjectOfClassType);
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 boolean indexBindingIsReachable(IIndexFileSet fileSet, IIndexBinding item) {
if (fileSet.containsDeclaration(item)) {
return true;
}
// Specializations of friend functions are sometimes created in the context
// of the file for which the AST is created, and which is thus not in the index
// file set. In some cases, an AST binding cannot be created for such
// specializations. To support these cases, consider the binding reachable if
// the friend function being specialized is reachable.
// This situation only arises in the presence of #includes that are not at
// global scope. Once bug 315964 is fixed, this workaround can be removed.
if (item instanceof ICPPFunctionSpecialization && !(item instanceof ICPPFunctionInstance)) {
IBinding specialized = ((ICPPFunctionSpecialization) item).getSpecializedBinding();
return !(specialized instanceof IIndexBinding)
|| fileSet.containsDeclaration((IIndexBinding) specialized);
}
return false;
}
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);
}
/**
* Similar to {@link CPPSemantics#findBindingsForContentAssist(IASTName, boolean, String[])},
* but in lieu of a name hooked up to the AST, accepts just a string, a position in the file
* (represented as an IASTNode, and used to serve as the point of reference for the lookup),
* and a starting scope (which is required).
*/
public static IBinding[] findBindingsForContentAssist(char[] name, boolean prefixLookup,
IScope lookupScope, IASTNode point) {
LookupData data = new LookupData(name, null, point);
data.contentAssist = true;
data.fHeuristicBaseLookup = true;
data.setPrefixLookup(prefixLookup);
data.foundItems = new CharArrayObjectMap<>(2);
try {
CPPSemantics.lookup(data, lookupScope);
} catch (DOMException e) {
}
return collectContentAssistBindings(data);
}
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) {
}
return collectContentAssistBindings(data);
}
private static IBinding[] collectContentAssistBindings(LookupData data) {
@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) {
// For declaration matching, compare the declared types (placeholders not resolved).
IType type = function.getDeclaredType();
return type.isSameType(CPPVisitor.createType(declarator, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS));
}
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) {
final char[] unknownName = unknown.getNameCharArray();
IASTNode point = CPPSemantics.getCurrentLookupPoint();
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;
}
public static void enablePromiscuousBindingResolution() {
fAllowPromiscuousBindingResolution.set(true);
}
public static void disablePromiscuousBindingResolution() {
fAllowPromiscuousBindingResolution.set(false);
}
public static boolean isUsingPromiscuousBindingResolution() {
return fAllowPromiscuousBindingResolution.get();
}
/**
* Compute decltype(expr) for an expression represented by an evaluation.
* This is similar to CPPVisitor.getDeclType(IASTExpression), but used in cases where the
* original expression was dependent, so we had to represent it as an evaluation and
* instantiate it.
*
* @param eval the (instantiated) evaluation representing the expression
*/
public static IType getDeclTypeForEvaluation(ICPPEvaluation eval) {
IType expressionType = eval.getType();
boolean namedEntity = eval instanceof EvalBinding || eval instanceof EvalMemberAccess;
if (!namedEntity && !(expressionType instanceof ICPPReferenceType)) {
switch (eval.getValueCategory()) {
case XVALUE:
return new CPPReferenceType(expressionType, true);
case LVALUE:
return new CPPReferenceType(expressionType, false);
case PRVALUE:
break;
}
}
return expressionType;
}
/**
* This method performs type deduction for auto, decltype or typeof
* declarations. This is used by {@code CSourceHover} and
* {@code OpenDeclarationsJob} after checking (see
* {@code SemanticUtil#isAutoOrDecltype(String)}) whether the selected text
* equals any of the mentioned keywords.
*
* @param node
* The decl-specifier or decltype-specifier in which the 'auto'
* or 'decltype' occurs.
* @return the deduced type or null
*/
public static IType resolveDecltypeOrAutoType(IASTNode node) {
IType type = null;
if (node instanceof ICPPASTDecltypeSpecifier) {
type = ((ICPPASTDecltypeSpecifier) node).getDecltypeExpression().getExpressionType();
}
if (node instanceof ICPPASTSimpleDeclSpecifier) {
int builtin = ((ICPPASTSimpleDeclSpecifier) node).getType();
if (builtin == ICPPASTSimpleDeclSpecifier.t_auto || builtin == ICPPASTSimpleDeclSpecifier.t_typeof
|| builtin == ICPPASTSimpleDeclSpecifier.t_decltype) {
IASTNode parent = node.getParent();
IASTDeclarator declarator = null;
if (parent instanceof IASTSimpleDeclaration) {
IASTDeclarator[] declarators = ((IASTSimpleDeclaration) parent).getDeclarators();
// It's invalid for different declarators to deduce
// different types with 'auto', so just get the type based on the
// first declarator.
if (declarators.length > 0)
declarator = declarators[0];
} else if (parent instanceof IASTParameterDeclaration
&& builtin != ICPPASTSimpleDeclSpecifier.t_auto) {
declarator = ((IASTParameterDeclaration) parent).getDeclarator();
} else if (parent instanceof ICPPASTTypeId && builtin != ICPPASTSimpleDeclSpecifier.t_auto) {
declarator = ((ICPPASTTypeId) parent).getAbstractDeclarator();
} else if (parent instanceof ICPPASTFunctionDefinition) {
declarator = ((ICPPASTFunctionDefinition) parent).getDeclarator();
}
if (declarator != null) {
type = CPPVisitor.createType(declarator);
if (type instanceof ICPPFunctionType) {
type = ((ICPPFunctionType) type).getReturnType();
}
}
}
}
return type;
}
}