| /******************************************************************************* |
| * Copyright (c) 2004, 2010 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 Corporation) - initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| * Bryan Wilkinson (QNX) |
| * Sergey Prigogin (Google) |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.dom.parser.cpp; |
| |
| import org.eclipse.cdt.core.dom.IName; |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.EScopeKind; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| 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.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; |
| import org.eclipse.cdt.core.index.IIndexFileSet; |
| import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; |
| |
| /** |
| * Models the scope represented by an unknown type (e.g.: typeof(template type parameter)). |
| * Used within the context of templates, only. For safe usage in index bindings, all fields need |
| * to be final or used in a thread-safe manner otherwise. |
| */ |
| public class CPPUnknownTypeScope implements ICPPInternalUnknownScope { |
| private final IASTName fName; |
| private final IType fScopeType; |
| /** |
| * This field needs to be protected when used in PDOMCPPUnknownScope, |
| * don't use it outside of {@link #getOrCreateBinding(IASTName, int)} |
| */ |
| private CharArrayObjectMap<IBinding[]> map; |
| |
| public CPPUnknownTypeScope(IType scopeType, IASTName name) { |
| fName= name; |
| fScopeType= scopeType; |
| } |
| |
| @Override |
| public EScopeKind getKind() { |
| return EScopeKind.eClassType; |
| } |
| |
| @Override |
| public IASTNode getPhysicalNode() { |
| return fName; |
| } |
| |
| @Override |
| public IName getScopeName() { |
| return fName; |
| } |
| |
| @Override |
| public IType getScopeType() { |
| return fScopeType; |
| } |
| |
| @Override |
| public IScope getParent() throws DOMException { |
| if (fScopeType instanceof IBinding) |
| return ((IBinding) fScopeType).getScope(); |
| return null; |
| } |
| |
| @Override |
| public IBinding[] find(String name) { |
| return IBinding.EMPTY_BINDING_ARRAY; |
| } |
| |
| @Override |
| public final IBinding getBinding(IASTName name, boolean resolve) { |
| return getBinding(name, resolve, IIndexFileSet.EMPTY); |
| } |
| |
| @Override |
| public IBinding getBinding(final IASTName name, boolean resolve, IIndexFileSet fileSet) { |
| boolean type= false; |
| boolean function= false; |
| |
| if (name.getPropertyInParent() == null) { |
| type= true; |
| } else { |
| IASTName n= name; |
| IASTNode parent= name.getParent(); |
| if (parent instanceof ICPPASTTemplateId) { |
| n= (IASTName) parent; |
| parent= n.getParent(); |
| } |
| if (parent instanceof ICPPASTQualifiedName) { |
| ICPPASTQualifiedName qname= (ICPPASTQualifiedName) parent; |
| if (qname.getLastName() != n) { |
| type= true; |
| } else { |
| parent= qname.getParent(); |
| } |
| } |
| if (!type) { |
| if (parent instanceof ICPPASTBaseSpecifier || |
| parent instanceof ICPPASTConstructorChainInitializer) { |
| type= true; |
| } else if (parent instanceof ICPPASTNamedTypeSpecifier) { |
| ICPPASTNamedTypeSpecifier nts= (ICPPASTNamedTypeSpecifier) parent; |
| type= nts.isTypename(); |
| } else if (parent instanceof ICPPASTUsingDeclaration) { |
| ICPPASTUsingDeclaration ud= (ICPPASTUsingDeclaration) parent; |
| type= ud.isTypename(); |
| function= true; |
| } |
| |
| if (!type && parent.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { |
| function= true; |
| } |
| } |
| } |
| |
| int idx= type ? 0 : function ? 1 : 2; |
| |
| IBinding result = getOrCreateBinding(name.getSimpleID(), idx); |
| return result; |
| } |
| |
| @Override @Deprecated |
| public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefix) { |
| return getBindings(name, resolve, prefix, IIndexFileSet.EMPTY); |
| } |
| |
| @Override @Deprecated |
| public final IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) { |
| return getBindings(new ScopeLookupData(name, resolve, prefixLookup)); |
| } |
| |
| @Override |
| public final IBinding[] getBindings(ScopeLookupData lookup) { |
| if (lookup.isPrefixLookup()) { |
| // If name lookup is performed for the purpose of code completion in a dependent context, |
| // try to give some useful results heuristically. |
| IScope scope = CPPSemantics.heuristicallyFindConcreteScopeForType(fScopeType, |
| lookup.getLookupPoint()); |
| if (scope != null) { |
| return scope.getBindings(lookup); |
| } |
| return IBinding.EMPTY_BINDING_ARRAY; |
| } |
| IASTName lookupName= lookup.getLookupName(); |
| if (lookupName != null) |
| return new IBinding[] { getBinding(lookupName, lookup.isResolve(), lookup.getIncludedFiles()) }; |
| |
| // When dealing with dependent expressions we always create an unknown class. That is because |
| // unknown objects are not used within the expressions, they are attached to names only. |
| return new IBinding[] { getOrCreateBinding(lookup.getLookupKey(), 0) }; |
| } |
| |
| @Override |
| public String toString() { |
| return fName.toString(); |
| } |
| |
| @Override |
| public void addName(IASTName name) { |
| } |
| |
| protected IBinding getOrCreateBinding(final char[] name, int idx) { |
| if (map == null) |
| map = new CharArrayObjectMap<>(2); |
| |
| IBinding[] o = map.get(name); |
| if (o == null) { |
| o = new IBinding[3]; |
| map.put(name, o); |
| } |
| |
| IBinding result= o[idx]; |
| if (result == null) { |
| switch (idx) { |
| case 0: |
| result= new CPPUnknownMemberClass(fScopeType, name); |
| break; |
| case 1: |
| result= new CPPUnknownMethod(fScopeType, name); |
| break; |
| case 2: |
| result= new CPPUnknownField(fScopeType, name); |
| break; |
| } |
| o[idx]= result; |
| } |
| return result; |
| } |
| |
| @Override |
| public void addBinding(IBinding binding) { |
| // Do nothing, this is part of template magic and not a normal scope. |
| } |
| |
| @Override |
| public void populateCache() {} |
| |
| @Override |
| public void removeNestedFromCache(IASTNode container) {} |
| |
| } |