/******************************************************************************* * 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 org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.ASTVisitor; 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.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; 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.ICPPASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; 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.parser.Keywords; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.model.ASTStringUtil; import org.eclipse.core.runtime.PlatformObject; public class CPPNamespace extends PlatformObject implements ICPPNamespace, ICPPInternalBinding { public static class CPPNamespaceProblem extends ProblemBinding implements ICPPNamespace, ICPPNamespaceScope{ public CPPNamespaceProblem(IASTNode node, int id, char[] arg) { super(node, id, arg); } public ICPPNamespaceScope getNamespaceScope() { return this; } public IBinding[] getMemberBindings() { return IBinding.EMPTY_BINDING_ARRAY; } public void addUsingDirective(ICPPUsingDirective usingDirective) { } public ICPPUsingDirective[] getUsingDirectives() { return ICPPUsingDirective.EMPTY_ARRAY; } public ICPPNamespaceScope[] getInlineNamespaces() { return ICPPNamespaceScope.EMPTY_NAMESPACE_SCOPE_ARRAY; } } private static final char[] EMPTY_CHAR_ARRAY = {}; IASTName[] namespaceDefinitions; ICPPNamespaceScope scope; ICPPASTTranslationUnit tu; public CPPNamespace(ICPPASTNamespaceDefinition nsDef) { findAllDefinitions(nsDef); if (namespaceDefinitions.length == 0) { namespaceDefinitions = new IASTName[] { nsDef.getName() }; } } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDeclarations() */ public IASTNode[] getDeclarations() { return namespaceDefinitions; } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDefinition() */ public IASTNode getDefinition() { return (tu != null) ? tu : (IASTNode) namespaceDefinitions[0]; } static private class NamespaceCollector extends ASTVisitor { private ICPPASTNamespaceDefinition namespaceDef = null; private IASTName[] namespaces = null; public NamespaceCollector(ICPPASTNamespaceDefinition ns ) { shouldVisitNamespaces = true; shouldVisitDeclarations = true; this.namespaceDef = ns; } @Override public int visit(ICPPASTNamespaceDefinition namespace) { ICPPASTNamespaceDefinition orig = namespaceDef, candidate = namespace; while(candidate != null) { if (!CharArrayUtils.equals(orig.getName().getLookupKey(), candidate.getName().getLookupKey())) return PROCESS_CONTINUE; if (orig.getParent() instanceof ICPPASTNamespaceDefinition) { if (!(candidate.getParent() instanceof ICPPASTNamespaceDefinition)) return PROCESS_CONTINUE; orig = (ICPPASTNamespaceDefinition) orig.getParent(); candidate = (ICPPASTNamespaceDefinition) candidate.getParent(); } else if (candidate.getParent() instanceof ICPPASTNamespaceDefinition) { return PROCESS_CONTINUE; } else { break; } } namespaces = (IASTName[]) ArrayUtil.append(IASTName.class, namespaces, namespace.getName()); return PROCESS_SKIP; } @Override public int visit(IASTDeclaration declaration) { if (declaration instanceof ICPPASTLinkageSpecification) return PROCESS_CONTINUE; return PROCESS_SKIP; } public IASTName[] getNamespaces() { return (IASTName[]) ArrayUtil.trim(IASTName.class, namespaces); } } static private class NamespaceMemberCollector extends ASTVisitor { public ObjectSet<IBinding> members = new ObjectSet<IBinding>(8); public NamespaceMemberCollector() { shouldVisitNamespaces = true; shouldVisitDeclarators = true; shouldVisitDeclSpecifiers = true; shouldVisitDeclarations = true; } @Override public int visit(IASTDeclarator declarator) { while(declarator.getNestedDeclarator() != null) declarator = declarator.getNestedDeclarator(); IBinding binding = declarator.getName().resolveBinding(); if (binding != null && !(binding instanceof IProblemBinding)) members.put(binding); return PROCESS_SKIP; } @Override public int visit(IASTDeclSpecifier declSpec) { if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { IBinding binding = ((ICPPASTCompositeTypeSpecifier)declSpec).getName().resolveBinding(); if (binding != null && !(binding instanceof IProblemBinding)) members.put(binding); return PROCESS_SKIP; } else if (declSpec instanceof ICPPASTElaboratedTypeSpecifier) { IASTNode parent = declSpec.getParent(); if (parent instanceof IASTSimpleDeclaration) { if (((IASTSimpleDeclaration)parent).getDeclarators().length > 0) return PROCESS_SKIP; IBinding binding = ((ICPPASTElaboratedTypeSpecifier)declSpec).getName().resolveBinding(); if (binding != null && !(binding instanceof IProblemBinding)) members.put(binding); return PROCESS_SKIP; } } return PROCESS_SKIP; } @Override public int visit(ICPPASTNamespaceDefinition namespace) { IBinding binding = namespace.getName().resolveBinding(); if (binding != null && !(binding instanceof IProblemBinding)) members.put(binding); return PROCESS_SKIP; } @Override public int visit(IASTDeclaration declaration) { if (declaration instanceof ICPPASTUsingDeclaration) { IBinding binding =((ICPPASTUsingDeclaration)declaration).getName().resolveBinding(); if (binding != null && !(binding instanceof IProblemBinding)) members.put(binding); return PROCESS_SKIP; } else if (declaration instanceof IASTFunctionDefinition) { return visit(((IASTFunctionDefinition)declaration).getDeclarator()); } return PROCESS_CONTINUE; } } private void findAllDefinitions(ICPPASTNamespaceDefinition namespaceDef) { NamespaceCollector collector = new NamespaceCollector(namespaceDef); namespaceDef.getTranslationUnit().accept(collector); namespaceDefinitions = collector.getNamespaces(); for (IASTName namespaceDefinition : namespaceDefinitions) { namespaceDefinition.setBinding(this); } } public IASTName[] getNamespaceDefinitions() { return namespaceDefinitions; } /** * @param unit */ public CPPNamespace(CPPASTTranslationUnit unit) { tu = unit; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace#getNamespaceScope() */ public ICPPNamespaceScope getNamespaceScope() { if (scope == null) { if (tu != null) scope = (ICPPNamespaceScope) tu.getScope(); else scope = new CPPNamespaceScope(namespaceDefinitions[0].getParent()); } return scope; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getName() */ public String getName() { return new String(getNameCharArray()); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray() */ public char[] getNameCharArray() { return tu != null ? EMPTY_CHAR_ARRAY : namespaceDefinitions[0].getSimpleID(); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getScope() */ public IScope getScope() { return tu != null ? null : CPPVisitor.getContainingScope(namespaceDefinitions[0]); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getPhysicalNode() */ public IASTNode getPhysicalNode() { return tu != null ? (IASTNode) tu : namespaceDefinitions[0]; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getFullyQualifiedName() */ public String[] getFullyQualifiedName() { return CPPVisitor.getQualifiedName(this); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getFullyQualifiedNameCharArray() */ public char[][] getFullyQualifiedNameCharArray() { return CPPVisitor.getQualifiedNameCharArray(this); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding#getQualifiedName() */ public String[] getQualifiedName() { return CPPVisitor.getQualifiedName(this); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding#getQualifiedNameCharArray() */ public char[][] getQualifiedNameCharArray() { return CPPVisitor.getQualifiedNameCharArray(this); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding#isGloballyQualified() */ public boolean isGloballyQualified() { return true; } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding#addDefinition(org.eclipse.cdt.core.dom.ast.IASTNode) */ public void addDefinition(IASTNode node) { if (!(node instanceof IASTName)) return; IASTName name = (IASTName) node; if (namespaceDefinitions == null) { namespaceDefinitions = new IASTName[] { name }; return; } if (namespaceDefinitions.length > 0 && ((ASTNode)name).getOffset() < ((ASTNode)namespaceDefinitions[0]).getOffset()) { namespaceDefinitions = (IASTName[]) ArrayUtil.prepend(IASTName.class, namespaceDefinitions, name); } else { namespaceDefinitions = (IASTName[]) ArrayUtil.append(IASTName.class, namespaceDefinitions, name); } } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding#addDeclaration(org.eclipse.cdt.core.dom.ast.IASTNode) */ public void addDeclaration(IASTNode node) { addDefinition(node); } public IBinding[] getMemberBindings() { if (namespaceDefinitions != null) { NamespaceMemberCollector collector = new NamespaceMemberCollector(); for (IASTName namespaceDefinition : namespaceDefinitions) { IASTNode parent = namespaceDefinition.getParent(); if (parent instanceof ICPPASTNamespaceDefinition) { IASTDeclaration[] decls = ((ICPPASTNamespaceDefinition)parent).getDeclarations(); for (IASTDeclaration decl : decls) { decl.accept(collector); } } } return collector.members.keyArray(IBinding.class); } return IBinding.EMPTY_BINDING_ARRAY; } public boolean isInline() { final ICPPNamespaceScope nsScope = getNamespaceScope(); if (nsScope instanceof CPPNamespaceScope) { return ((CPPNamespaceScope) nsScope).isInlineNamepace(); } return false; } public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } @Override public String toString() { String[] names = getQualifiedName(); if (names.length == 0) { return "<unnamed namespace>"; //$NON-NLS-1$ } return ASTStringUtil.join(names, String.valueOf(Keywords.cpCOLONCOLON)); } public IBinding getOwner() { if (namespaceDefinitions != null && namespaceDefinitions.length > 0) { return CPPVisitor.findDeclarationOwner(namespaceDefinitions[0], false); } return null; } }