/*******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* 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.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;
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.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
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.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
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.ICPPUsingDeclaration;
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.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;
/**
* Context data for IASTName lookup
*/
public class LookupData {
protected IASTName astName;
protected CPPASTTranslationUnit tu;
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<IScope>(1);
public boolean checkWholeClassScope = false;
public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false;
public boolean forceQualified = false;
public boolean forAssociatedScopes = false;
public boolean contentAssist = false;
public boolean prefixLookup = false;
public boolean typesOnly = false;
/** For lookup of unknown bindings the point of declaration can be reversed. */
public boolean checkPointOfDecl= true;
/** For field references or qualified names, enclosing template declarations are ignored. */
public boolean usesEnclosingScope= true;
/** When computing the cost of a method call, treat the first argument as the implied object. */
public boolean argsContainImpliedObject = false;
public boolean ignoreMembers = false;
/** In list-initialization **/
public boolean fNoNarrowing= false;
private IASTInitializerClause[] functionArgs;
private IType[] functionArgTypes;
private ValueCategory[] functionArgValueCategories;
public ICPPClassType skippedScope;
public Object foundItems = null;
public ProblemBinding problem;
public LookupData(IASTName n) {
astName = n;
tu= (CPPASTTranslationUnit) astName.getTranslationUnit();
typesOnly = typesOnly(astName);
checkWholeClassScope = checkWholeClassScope(n);
}
public LookupData() {
astName = null;
}
public final char[] getNameCharArray() {
if (astName != null)
return astName.toCharArray();
return CharArrayUtils.EMPTY;
}
public boolean includeBlockItem(IASTNode item) {
if (astName.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY) return true;
if ((astName != null && astName.getParent() instanceof IASTIdExpression) ||
item instanceof ICPPASTNamespaceDefinition ||
(item instanceof IASTSimpleDeclaration && ((IASTSimpleDeclaration) item).getDeclSpecifier() instanceof IASTCompositeTypeSpecifier) ||
item instanceof ICPPASTTemplateDeclaration) {
return true;
}
return false;
}
static boolean typesOnly(IASTName name) {
if (name == null) return false;
if (name.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY) return false;
IASTNode parent = name.getParent();
if (parent instanceof ICPPASTBaseSpecifier || parent instanceof ICPPASTElaboratedTypeSpecifier ||
parent instanceof ICPPASTCompositeTypeSpecifier)
return true;
if (parent instanceof ICPPASTQualifiedName) {
IASTName[] ns = ((ICPPASTQualifiedName) parent).getNames();
return (name != ns[ns.length -1]);
}
return false;
}
public boolean forUsingDeclaration() {
if (astName == null) return false;
if (astName.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY) return false;
IASTNode p1 = astName.getParent();
if (p1 instanceof ICPPASTUsingDeclaration)
return true;
if (p1 instanceof ICPPASTQualifiedName) {
IASTNode p2 = p1.getParent();
if (p2 instanceof ICPPASTUsingDeclaration) {
IASTName[] ns = ((ICPPASTQualifiedName) p1).getNames();
return (ns[ns.length - 1] == astName);
}
}
return false;
}
/**
* Returns whether the name belongs to a simple declaration or function definition.
*/
public IASTDeclaration forDeclaration() {
IASTNode node = getDeclarator();
while (node instanceof IASTDeclarator)
node= node.getParent();
if (node instanceof IASTSimpleDeclaration || node instanceof IASTFunctionDefinition)
return (IASTDeclaration) node;
return null;
}
public IASTDeclarator getDeclarator() {
IASTName name= astName;
if (name == null || name.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY)
return null;
if (name.getParent() instanceof ICPPASTTemplateId)
name= (IASTName) name.getParent();
IASTNode node= name.getParent();
if (node instanceof ICPPASTQualifiedName) {
if (((ICPPASTQualifiedName) node).getLastName() != name)
return null;
node = node.getParent();
}
if (node instanceof IASTDeclarator)
return (IASTDeclarator) node;
return null;
}
public boolean forExplicitFunctionSpecialization() {
IASTDeclaration decl= forDeclaration();
if (decl != null) {
IASTName n = astName;
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 qualified() {
if (forceQualified)
return true;
IASTName n= astName;
if (n == null || n.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY)
return false;
IASTNode p = n.getParent();
if (p instanceof ICPPASTTemplateId) {
n= (IASTName) p;
p= p.getParent();
}
if (p instanceof ICPPASTQualifiedName) {
final ICPPASTQualifiedName qname = (ICPPASTQualifiedName) p;
if (qname.isFullyQualified())
return true;
final IASTName[] qnames = qname.getNames();
if (qnames.length > 0 && qnames[0] != n)
return true;
}
return p instanceof ICPPASTFieldReference;
}
public boolean isFunctionCall() {
if (astName == null) return false;
if (astName.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY) return false;
IASTNode p1 = astName.getParent();
if (p1 instanceof ICPPASTQualifiedName)
p1 = p1.getParent();
return (p1 instanceof IASTIdExpression && p1.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME);
}
public static boolean checkWholeClassScope(IASTName name) {
if (name == null)
return false;
if (name.getPropertyInParent() == CPPSemantics.STRING_LOOKUP_PROPERTY)
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 == 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 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 hasTypeOrMemberFunctionResult() {
if (foundItems == null)
return false;
if (foundItems instanceof Object[]) {
for (Object item : (Object[]) foundItems) {
if (item instanceof ICPPMethod || item instanceof IType) {
return true;
}
}
}
return false;
}
/**
* Returns the implied object type, or <code>null</code>.
*/
public IType getImpliedObjectType() {
if (astName == null)
return null;
IASTName name= astName;
IASTNode nameParent= name.getParent();
while (nameParent instanceof IASTName) {
name= (IASTName) nameParent;
nameParent= name.getParent();
}
final ASTNodeProperty prop = name.getPropertyInParent();
if (prop == CPPSemantics.STRING_LOOKUP_PROPERTY) {
return null;
}
if (prop == IASTFieldReference.FIELD_NAME) {
ICPPASTFieldReference fieldRef = (ICPPASTFieldReference) nameParent;
return fieldRef.getFieldOwnerType();
}
if (prop == IASTIdExpression.ID_NAME) {
IScope scope = CPPVisitor.getContainingScope(name);
if (scope instanceof ICPPClassScope) {
return ((ICPPClassScope) scope).getClassType();
}
return CPPVisitor.getImpliedObjectType(scope);
}
return null;
}
public boolean forFriendship() {
if (astName == null)
return false;
IASTNode node = astName.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() {
IASTName name= astName;
if (name == null || name instanceof ICPPASTQualifiedName)
return false;
IASTNode parent = name.getParent();
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME)
parent= parent.getParent();
if (parent instanceof ICPPASTQualifiedName) {
return false;
}
return isFunctionCall();
}
public boolean checkClassContainingFriend() {
if (astName == null || astName instanceof ICPPASTQualifiedName)
return false;
IASTNode p = astName.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, IASTInitializerClause... exprs) {
argsContainImpliedObject= containsImpliedObject;
functionArgs= exprs;
if (exprs.length != 0) {
IASTNode node= exprs[0];
boolean checkForDependentName= false;
while (node != null) {
if (node instanceof ICPPASTTemplateDeclaration) {
checkForDependentName= true;
break;
}
node= node.getParent();
}
if (checkForDependentName) {
IType[] types= getFunctionArgumentTypes();
for (IType type : types) {
if (CPPTemplates.isDependentType(type)) {
checkPointOfDecl= false;
break;
}
}
}
}
}
public IType[] getFunctionArgumentTypes() {
if (functionArgTypes == null) {
if (functionArgs != null) {
IASTInitializerClause[] exprs= functionArgs;
functionArgTypes= new IType[exprs.length];
for (int i = 0; i < exprs.length; i++) {
IASTInitializerClause e = exprs[i];
if (e instanceof IASTExpression) {
// Find function set when taking an address of a function
final IType t = ExpressionTypes.typeOrFunctionSet((IASTExpression) e);
functionArgTypes[i]= getSimplifiedType(t);
} else if (e instanceof ICPPASTInitializerList) {
functionArgTypes[i]= new InitializerListType((ICPPASTInitializerList) e);
}
}
}
}
return functionArgTypes;
}
public ValueCategory[] getFunctionArgumentValueCategories() {
if (functionArgValueCategories == null) {
IASTInitializerClause[] args= functionArgs;
if (args != null) {
functionArgValueCategories= new ValueCategory[args.length];
for (int i = 0; i < args.length; i++) {
final IASTInitializerClause arg = args[i];
if (arg instanceof IASTExpression) {
functionArgValueCategories[i] = ExpressionTypes.valueCat((IASTExpression) arg);
}
}
}
}
return functionArgValueCategories;
}
public int getFunctionArgumentCount() {
if (functionArgs != null)
return functionArgs.length;
return 0;
}
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;
}
}