blob: 8f20cd4ed5a6465e335fa542d40f15ecd769e8eb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2015 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:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getSimplifiedType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
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.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator;
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.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
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.ICPPASTTemplateSpecialization;
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.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPCompositeBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
/**
* Context data for IASTName lookup
*/
public class LookupData extends ScopeLookupData {
private static final ICPPTemplateArgument[] UNINITIALIZED_TEMPLATE_ARGUMENTS = {};
public Map<ICPPNamespaceScope, List<ICPPNamespaceScope>> usingDirectives= Collections.emptyMap();
/** Used to ensure we don't visit things more than once. */
public ObjectSet<IScope> visited= new ObjectSet<>(1);
public boolean contentAssist;
public boolean typesOnly;
public boolean usingDirectivesOnly;
public boolean ignoreUsingDirectives;
public boolean ignoreMembers;
public boolean qualified;
public boolean forUsingDeclaration;
public boolean namespacesOnly;
/** When computing the cost of a method call, treat the first argument as the implied object. */
public boolean argsContainImpliedObject;
/** In list-initialization **/
public boolean fNoNarrowing;
/** When doing lookup in base classes, replace deferred class instances with their class template.
* This is used by editor actions like content assist. */
public boolean fHeuristicBaseLookup;
private IASTDeclarator fDeclarator;
private boolean fFunctionCall;
private IType fImpliedObjectType;
private ValueCategory fImpliedObjectValueCategory;
private ICPPEvaluation[] functionArgs;
private IType[] functionArgTypes;
private ValueCategory[] functionArgValueCategories;
private ICPPTemplateArgument[] fTemplateArguments = UNINITIALIZED_TEMPLATE_ARGUMENTS;
public ICPPClassType skippedScope;
public Object foundItems;
public ProblemBinding problem;
public LookupData(IASTName name) {
super(name, true, false);
fTemplateArguments = UNINITIALIZED_TEMPLATE_ARGUMENTS; // Lazy initialization to avoid DOMException.
configureWith(name);
}
public LookupData(char[] name, ICPPTemplateArgument[] templateArgs, IASTNode lookupPoint) {
super(name, lookupPoint);
fTemplateArguments= templateArgs;
}
public LookupData(char[] name, ICPPTemplateArgument[] templateArgs, IASTTranslationUnit tu) {
super(name, tu);
fTemplateArguments= templateArgs;
}
@Override
public CPPASTTranslationUnit getTranslationUnit() {
return (CPPASTTranslationUnit) super.getTranslationUnit();
}
private void configureWith(final IASTName name) {
IASTName tn= name;
if (tn.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
tn= (IASTName) tn.getParent();
}
IASTNode parent = tn.getParent();
IASTNode nameParent= parent;
if (parent instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qn = (ICPPASTQualifiedName) parent;
if (qn.getLastName() != tn) {
// For resolving template id ambiguities we need to consider non-types.
if (!(tn instanceof ICPPASTTemplateId)) {
typesOnly= true;
}
} else {
nameParent= parent.getParent();
}
final ICPPASTNameSpecifier[] qualifier = qn.getQualifier();
if (qn.isFullyQualified()) {
qualified= true;
} else if (qualifier.length > 0) {
if (qualifier[0] != tn) {
qualified= true;
}
}
}
if (nameParent instanceof ICPPASTBaseSpecifier
|| nameParent instanceof ICPPASTElaboratedTypeSpecifier
|| nameParent instanceof ICPPASTCompositeTypeSpecifier) {
typesOnly= true;
} else if (nameParent instanceof ICPPASTUsingDeclaration) {
forUsingDeclaration= true;
} else if (nameParent instanceof ICPPASTUsingDirective || nameParent instanceof ICPPASTNamespaceAlias) {
// [basic.lookup.udir]: Only namespace names are considered
namespacesOnly= true;
} else if (nameParent instanceof IASTDeclarator) {
fDeclarator= (IASTDeclarator) nameParent;
} else if (nameParent instanceof IASTFieldReference) {
qualified= true;
if (nameParent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
fFunctionCall= true;
}
} else if (nameParent instanceof IASTIdExpression) {
if (nameParent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
fFunctionCall= true;
}
}
}
/**
* Returns whether the name belongs to a simple declaration or function definition.
*/
public IASTDeclaration forDeclaration() {
IASTNode node = fDeclarator;
while (node instanceof IASTDeclarator)
node= node.getParent();
if (node instanceof IASTSimpleDeclaration || node instanceof IASTFunctionDefinition)
return (IASTDeclaration) node;
return null;
}
public IASTDeclarator getDeclarator() {
return fDeclarator;
}
public boolean forExplicitFunctionSpecialization() {
IASTName n = getLookupName();
if (n == null)
return false;
IASTDeclaration decl= forDeclaration();
if (decl != null) {
if (n.getParent() instanceof ICPPASTTemplateId)
n = (IASTName) n.getParent();
ICPPASTTemplateDeclaration tmplDecl = CPPTemplates.getTemplateDeclaration(n);
return tmplDecl instanceof ICPPASTTemplateSpecialization;
}
return false;
}
public boolean forExplicitFunctionInstantiation() {
IASTDeclaration decl= forDeclaration();
return decl != null && decl.getParent() instanceof ICPPASTExplicitTemplateInstantiation;
}
public boolean isFunctionCall() {
return fFunctionCall;
}
public static boolean checkWholeClassScope(IASTName name) {
if (name == null)
return true;
IASTNode node = name.getParent();
while (node instanceof IASTName) {
name= (IASTName) node;
node= name.getParent();
}
final ASTNodeProperty nameProp = name.getPropertyInParent();
if (nameProp == IASTIdExpression.ID_NAME ||
nameProp == IASTFieldReference.FIELD_NAME ||
nameProp == ICASTFieldDesignator.FIELD_NAME ||
nameProp == ICPPASTFieldDesignator.FIELD_NAME ||
nameProp == ICPPASTUsingDirective.QUALIFIED_NAME ||
nameProp == ICPPASTUsingDeclaration.NAME ||
nameProp == IASTFunctionCallExpression.FUNCTION_NAME ||
nameProp == IASTNamedTypeSpecifier.NAME ||
nameProp == ICPPASTConstructorChainInitializer.MEMBER_ID) {
// Potentially we need to consider the entire class scope
} else {
return false;
}
for (; node != null; node= node.getParent()) {
// 3.3.7-5
if (node.getParent() instanceof IASTFunctionDefinition) {
// In a function body
final ASTNodeProperty prop = node.getPropertyInParent();
if (prop == IASTFunctionDefinition.DECL_SPECIFIER ||
prop == IASTFunctionDefinition.DECLARATOR) {
return false;
}
IASTNode parent = node.getParent();
while (parent != null) {
if (parent instanceof ICPPASTCompositeTypeSpecifier)
return true;
parent= parent.getParent();
}
// No inline method.
return false;
}
if (node instanceof IASTInitializerList || node instanceof IASTEqualsInitializer) {
if (node.getPropertyInParent() == IASTDeclarator.INITIALIZER) {
IASTNode decl= node.getParent();
while (decl instanceof IASTDeclarator) {
decl= decl.getParent();
}
if (decl instanceof IASTParameterDeclaration) {
// Default argument
IASTNode parent = decl.getParent();
while (parent != null) {
if (parent instanceof ICPPASTCompositeTypeSpecifier)
return true;
parent= parent.getParent();
}
// Not within a class definition
return false;
}
if (decl instanceof IASTSimpleDeclaration &&
decl.getPropertyInParent() == IASTCompositeTypeSpecifier.MEMBER_DECLARATION) {
// Initializer of non-static data member
IASTDeclSpecifier declSpec= ((IASTSimpleDeclaration) decl).getDeclSpecifier();
if (declSpec.getStorageClass() != IASTDeclSpecifier.sc_static) {
return true;
}
// Continue search, we could still be in a method.
}
}
}
}
return false;
}
public static boolean typesOnly(IASTName tn) {
if (tn.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
tn= (IASTName) tn.getParent();
}
IASTNode parent = tn.getParent();
if (parent instanceof ICPPASTBaseSpecifier
|| parent instanceof ICPPASTElaboratedTypeSpecifier
|| parent instanceof ICPPASTCompositeTypeSpecifier) {
return true;
} else if (parent instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qn = (ICPPASTQualifiedName) parent;
if (qn.getLastName() != tn) {
return true;
}
}
return false;
}
public boolean hasResultOrProblem() {
return problem != null || hasResults();
}
public boolean hasResults() {
if (foundItems == null)
return false;
if (foundItems instanceof Object[])
return ((Object[]) foundItems).length != 0;
if (foundItems instanceof CharArrayObjectMap)
return ((CharArrayObjectMap<?>) foundItems).size() != 0;
return false;
}
public boolean hasTypeOrMemberFunctionOrVariableResult() {
if (foundItems == null)
return false;
if (foundItems instanceof Object[]) {
for (Object item : (Object[]) foundItems) {
if (item instanceof ICPPMethod || item instanceof IType || item instanceof IVariable) {
return true;
}
}
}
return false;
}
/**
* Returns the implied object type, or {@code null} if there is no implied object.
*/
public IType getImpliedObjectType() {
if (fImpliedObjectType == null) {
fImpliedObjectType= determineImpliedObjectType();
}
return fImpliedObjectType;
}
/**
* Explicitly sets the implied object type.
* This method is for use in cases where implied object type cannot
* be determined automatically because there is no lookup name.
*/
public void setImpliedObjectType(IType impliedObjectType) {
fImpliedObjectType = impliedObjectType;
}
private IType determineImpliedObjectType() {
IASTName tn = getLookupName();
if (tn == null)
return null;
if (tn.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
tn= (IASTName) tn.getParent();
}
IASTNode parent = tn.getParent();
IASTNode nameParent= parent;
if (parent instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qn = (ICPPASTQualifiedName) parent;
if (qn.getLastName() == tn) {
nameParent= parent.getParent();
}
}
if (nameParent instanceof IASTFieldReference) {
return ((ICPPASTFieldReference) nameParent).getFieldOwnerType();
} else if (nameParent instanceof IASTIdExpression) {
if (nameParent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
IScope scope = CPPVisitor.getContainingScope(nameParent);
if (scope instanceof ICPPClassScope) {
return ((ICPPClassScope) scope).getClassType();
} else {
return CPPVisitor.getImpliedObjectType(scope);
}
}
}
return null;
}
/**
* Returns the category of the implied object, or {@code null} if there is no implied object.
* @see ValueCategory
*/
public ValueCategory getImpliedObjectValueCategory() {
if (fImpliedObjectValueCategory == null) {
fImpliedObjectValueCategory= determineImpliedObjectValueCategory();
}
return fImpliedObjectValueCategory;
}
private ValueCategory determineImpliedObjectValueCategory() {
IASTName tn = getLookupName();
if (tn == null)
return null;
if (tn.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
tn= (IASTName) tn.getParent();
}
IASTNode parent = tn.getParent();
IASTNode nameParent= parent;
if (parent instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qn = (ICPPASTQualifiedName) parent;
if (qn.getLastName() == tn) {
nameParent= parent.getParent();
}
}
if (nameParent instanceof IASTFieldReference) {
ICPPASTFieldReference fieldReference = (ICPPASTFieldReference) nameParent;
ICPPASTExpression owner = fieldReference.getFieldOwner();
if (fieldReference.isPointerDereference()) {
return ValueCategory.LVALUE;
}
return owner.getValueCategory();
} else if (nameParent instanceof IASTIdExpression) {
return ValueCategory.LVALUE;
}
return null;
}
public boolean forFriendship() {
IASTName lookupName= getLookupName();
if (lookupName == null)
return false;
IASTNode node = lookupName.getParent();
while (node instanceof IASTName)
node = node.getParent();
IASTDeclaration decl = null;
IASTDeclarator dtor = null;
if (node instanceof ICPPASTDeclSpecifier && node.getParent() instanceof IASTDeclaration) {
decl = (IASTDeclaration) node.getParent();
} else if (node instanceof IASTDeclarator) {
dtor = (IASTDeclarator) node;
while (dtor.getParent() instanceof IASTDeclarator)
dtor = (IASTDeclarator) dtor.getParent();
if (!(dtor.getParent() instanceof IASTDeclaration))
return false;
decl = (IASTDeclaration) dtor.getParent();
} else {
return false;
}
if (decl instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simple = (IASTSimpleDeclaration) decl;
if (!((ICPPASTDeclSpecifier) simple.getDeclSpecifier()).isFriend())
return false;
if (dtor != null)
return true;
return simple.getDeclarators().length == 0;
} else if (decl instanceof IASTFunctionDefinition) {
IASTFunctionDefinition fnDef = (IASTFunctionDefinition) decl;
if (!((ICPPASTDeclSpecifier) fnDef.getDeclSpecifier()).isFriend())
return false;
return (dtor != null);
}
return false;
}
public boolean checkAssociatedScopes() {
return !qualified && fFunctionCall;
}
public boolean checkClassContainingFriend() {
IASTName lookupName= getLookupName();
if (lookupName == null || lookupName instanceof ICPPASTQualifiedName)
return false;
IASTNode p = lookupName.getParent();
ASTNodeProperty prop = null;
while (p != null) {
prop = p.getPropertyInParent();
if (prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == IASTDeclarator.DECLARATOR_NAME)
return false;
if (p instanceof IASTDeclarator && !(((IASTDeclarator) p).getName() instanceof ICPPASTQualifiedName))
return false;
if (p instanceof IASTDeclaration) {
if (prop == IASTCompositeTypeSpecifier.MEMBER_DECLARATION) {
return CPPVisitor.isFriendDeclaration(p);
} else {
return false;
}
}
p = p.getParent();
}
return false;
}
public void setFunctionArguments(boolean containsImpliedObject, ICPPEvaluation... exprs) {
argsContainImpliedObject= containsImpliedObject;
functionArgs= exprs;
functionArgTypes = null;
}
public void setFunctionArguments(boolean containsImpliedObject, IASTInitializerClause... exprs) {
ICPPEvaluation[] evals= new ICPPEvaluation[exprs.length];
for (int i = 0; i < evals.length; i++) {
evals[i]= ((ICPPASTInitializerClause) exprs[i]).getEvaluation();
}
setFunctionArguments(containsImpliedObject, evals);
}
public IType[] getFunctionArgumentTypes() {
if (functionArgTypes == null && functionArgs != null) {
functionArgTypes= new IType[functionArgs.length];
for (int i = 0; i < functionArgs.length; i++) {
ICPPEvaluation e = functionArgs[i];
functionArgTypes[i]= getSimplifiedType(e.getType(getLookupPoint()));
}
}
return functionArgTypes;
}
public ValueCategory[] getFunctionArgumentValueCategories() {
if (functionArgValueCategories == null) {
ICPPEvaluation[] args= functionArgs;
if (args != null) {
functionArgValueCategories= new ValueCategory[args.length];
for (int i = 0; i < args.length; i++) {
final ICPPEvaluation arg = args[i];
functionArgValueCategories[i] = arg.getValueCategory(getLookupPoint());
}
}
}
return functionArgValueCategories;
}
public ICPPTemplateArgument[] getTemplateArguments() throws DOMException {
if (fTemplateArguments == UNINITIALIZED_TEMPLATE_ARGUMENTS) {
IASTName name = getLookupName();
if (name instanceof ICPPASTTemplateId) {
fTemplateArguments = CPPTemplates.createTemplateArgumentArray((ICPPASTTemplateId) name);
} else {
fTemplateArguments = null;
}
}
return fTemplateArguments;
}
void setTemplateArguments(ICPPTemplateArgument[] fTemplateArguments) {
this.fTemplateArguments = fTemplateArguments;
}
public int getFunctionArgumentCount() {
if (functionArgs != null)
return functionArgs.length;
return 0;
}
public int getFunctionArgumentPackExpansionCount() {
int count= 0;
if (functionArgs != null) {
for (ICPPEvaluation arg : functionArgs) {
if (arg instanceof EvalParameterPack)
count++;
}
}
return count;
}
public boolean hasFunctionArguments() {
return functionArgs != null;
}
public IBinding[] getFoundBindings() {
if (foundItems instanceof Object[]) {
Object[] items = (Object[]) foundItems;
if (items.length != 0) {
IBinding[] bindings = new IBinding[items.length];
int k = 0;
for (Object item : items) {
// Exclude using declarations, they have been expanded at this point.
if (item instanceof IBinding && !(item instanceof ICPPUsingDeclaration)
&& !(item instanceof CPPCompositeBinding)) {
bindings[k++] = (IBinding) item;
}
}
if (k != 0) {
return ArrayUtil.trimAt(IBinding.class, bindings, k - 1);
}
}
}
return IBinding.EMPTY_BINDING_ARRAY;
}
public boolean ignoreRecursionResolvingBindings() {
// When name lookup is performed during template instantiation
// rather than for an AST name, infinite recursion can sometimes
// result when a binding with a given name uses the same name
// in its definition (e.g. "typedef C::name name" where C is
// the current (template) class). In such cases, we want to
// ignore the resulting IRecursionResolvingBindings and allow
// name lookup to proceed to outer (or base class) scopes.
return getLookupName() == null;
}
}