/******************************************************************************* * 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) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IName; 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.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; 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.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScopeMapper.InlineNamespaceDirective; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.core.runtime.CoreException; /** * Implementation of namespace scopes, including global scope. */ public class CPPNamespaceScope extends CPPScope implements ICPPInternalNamespaceScope { private static final ICPPInternalNamespaceScope[] NO_NAMESPACE_SCOPES = new ICPPInternalNamespaceScope[0]; private List<ICPPUsingDirective> fUsingDirectives = null; private boolean fIsInline; private boolean fIsInlineInitialized; private ICPPNamespaceScope[] fEnclosingNamespaceSet; private List<ICPPASTNamespaceDefinition> fInlineNamespaceDefinitions; private ICPPInternalNamespaceScope[] fInlineNamespaces; public CPPNamespaceScope(IASTNode physicalNode) { super(physicalNode); } public EScopeKind getKind() { if (getPhysicalNode() instanceof IASTTranslationUnit) return EScopeKind.eGlobal; return EScopeKind.eNamespace; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope#getUsingDirectives() */ public ICPPUsingDirective[] getUsingDirectives() { initUsingDirectives(); populateCache(); return fUsingDirectives.toArray(new ICPPUsingDirective[fUsingDirectives.size()]); } private void initUsingDirectives() { if (fUsingDirectives == null) { fUsingDirectives= new ArrayList<ICPPUsingDirective>(1); // Insert a using directive for every inline namespace found in the index for (ICPPInternalNamespaceScope inline: getIndexInlineNamespaces()) { if (!(inline instanceof CPPNamespaceScope)) { fUsingDirectives.add(new InlineNamespaceDirective(this, inline)); } } } } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope#addUsingDirective(org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective) */ public void addUsingDirective(ICPPUsingDirective directive) { initUsingDirectives(); fUsingDirectives.add(directive); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPScope#getScopeName() */ @Override public IName getScopeName() { IASTNode node = getPhysicalNode(); if (node instanceof ICPPASTNamespaceDefinition) { return ((ICPPASTNamespaceDefinition) node).getName(); } return null; } public IScope findNamespaceScope(IIndexScope scope) { final String[] qname= CPPVisitor.getQualifiedName(scope.getScopeBinding()); final IScope[] result= {null}; final ASTVisitor visitor= new ASTVisitor() { private int depth= 0; { shouldVisitNamespaces= shouldVisitDeclarations= true; } @Override public int visit( IASTDeclaration declaration ){ if (declaration instanceof ICPPASTLinkageSpecification) return PROCESS_CONTINUE; return PROCESS_SKIP; } @Override public int visit(ICPPASTNamespaceDefinition namespace) { final String name = namespace.getName().toString(); if (name.length() == 0) { return PROCESS_CONTINUE; } if (qname[depth].equals(name)) { if (++depth == qname.length) { result[0]= namespace.getScope(); return PROCESS_ABORT; } return PROCESS_CONTINUE; } return PROCESS_SKIP; } @Override public int leave(ICPPASTNamespaceDefinition namespace) { if (namespace.getName().getLookupKey().length > 0) { --depth; } return PROCESS_CONTINUE; } }; getPhysicalNode().accept(visitor); return result[0]; } public boolean isInlineNamepace() { if (!fIsInlineInitialized) { fIsInline= computeIsInline(); fIsInlineInitialized= true; } return fIsInline; } public boolean computeIsInline() { final IASTNode node= getPhysicalNode(); if (!(node instanceof ICPPASTNamespaceDefinition)) { return false; } if (((ICPPASTNamespaceDefinition) node).isInline()) return true; IASTTranslationUnit tu= node.getTranslationUnit(); if (tu != null) { final IIndex index= tu.getIndex(); IIndexFileSet fileSet= tu.getASTFileSet(); if (index != null && fileSet != null) { fileSet= fileSet.invert(); ICPPNamespace nsBinding = getNamespaceIndexBinding(index); if (nsBinding != null && nsBinding.isInline()) { try { IIndexName[] names = index.findDefinitions(nsBinding); for (IIndexName name : names) { if (name.isInlineNamespaceDefinition() && fileSet.contains(name.getFile())) { return true; } } } catch (CoreException e) { CCorePlugin.log(e); } } } } return false; } public ICPPNamespaceScope[] getEnclosingNamespaceSet() { if (fEnclosingNamespaceSet == null) { return fEnclosingNamespaceSet= computeEnclosingNamespaceSet(this); } return fEnclosingNamespaceSet; } public ICPPInternalNamespaceScope[] getInlineNamespaces() { if (getKind() == EScopeKind.eLocal) return NO_NAMESPACE_SCOPES; if (fInlineNamespaces == null) { fInlineNamespaces= computeInlineNamespaces(); } return fInlineNamespaces; } ICPPInternalNamespaceScope[] computeInlineNamespaces() { populateCache(); Set<ICPPInternalNamespaceScope> result= null; if (fInlineNamespaceDefinitions != null) { result= new HashSet<ICPPInternalNamespaceScope>(fInlineNamespaceDefinitions.size()); for (ICPPASTNamespaceDefinition nsdef : fInlineNamespaceDefinitions) { final IScope scope = nsdef.getScope(); if (scope instanceof ICPPInternalNamespaceScope) { result.add((ICPPInternalNamespaceScope) scope); } } } for (ICPPInternalNamespaceScope inline : getIndexInlineNamespaces()) { if (result == null) result = new HashSet<ICPPInternalNamespaceScope>(); result.add(inline); } if (result == null) { return NO_NAMESPACE_SCOPES; } return result.toArray(new ICPPInternalNamespaceScope[result.size()]); } private ICPPInternalNamespaceScope[] getIndexInlineNamespaces() { IASTTranslationUnit tu= getPhysicalNode().getTranslationUnit(); if (tu instanceof CPPASTTranslationUnit) { CPPASTTranslationUnit cpptu= (CPPASTTranslationUnit) tu; IIndex index= tu.getIndex(); if (index != null) { IScope[] inlineScopes= null; ICPPNamespace namespace= getNamespaceIndexBinding(index); try { if (namespace != null) { ICPPNamespaceScope scope = namespace.getNamespaceScope(); inlineScopes= scope.getInlineNamespaces(); } else if (getKind() == EScopeKind.eGlobal) { inlineScopes= index.getInlineNamespaces(); } } catch (CoreException e) { } if (inlineScopes != null) { List<ICPPInternalNamespaceScope> result= null; for (IScope scope : inlineScopes) { if (scope instanceof IIndexScope) { scope= cpptu.mapToASTScope((IIndexScope) scope); } if (scope instanceof ICPPInternalNamespaceScope) { if (result == null) { result= new ArrayList<ICPPInternalNamespaceScope>(); } result.add((ICPPInternalNamespaceScope) scope); } } if (result != null) { return result.toArray(new ICPPInternalNamespaceScope[result.size()]); } } } } return NO_NAMESPACE_SCOPES; } /** * Called while populating scope. */ public void addInlineNamespace(ICPPASTNamespaceDefinition nsDef) { if (fInlineNamespaceDefinitions == null) { fInlineNamespaceDefinitions= new ArrayList<ICPPASTNamespaceDefinition>(); } fInlineNamespaceDefinitions.add(nsDef); } public static ICPPNamespaceScope[] computeEnclosingNamespaceSet(ICPPInternalNamespaceScope nsScope) { if (nsScope.isInlineNamepace()) { try { IScope parent= nsScope.getParent(); if (parent instanceof ICPPInternalNamespaceScope) { return ((ICPPInternalNamespaceScope) parent).getEnclosingNamespaceSet(); } } catch (DOMException e) { CCorePlugin.log(e); } } Set<ICPPInternalNamespaceScope> result= new HashSet<ICPPInternalNamespaceScope>(); result.add(nsScope); addInlineNamespaces(nsScope, result); return result.toArray(new ICPPNamespaceScope[result.size()]); } private static void addInlineNamespaces(ICPPInternalNamespaceScope nsScope, Set<ICPPInternalNamespaceScope> result) { ICPPInternalNamespaceScope[] inlineNss = nsScope.getInlineNamespaces(); for (ICPPInternalNamespaceScope inlineNs : inlineNss) { if (result.add(inlineNs)) { addInlineNamespaces(inlineNs, result); } } } }