/******************************************************************************* * Copyright (c) 2004, 2014 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) * Sergey Prigogin (Google) * Nathan Ridge *******************************************************************************/ 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.DOMException; 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.IASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; 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.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; 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.ICPPBlockScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.Linkage; 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.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.core.runtime.PlatformObject; /** * Enumeration in C++ */ public class CPPEnumeration extends PlatformObject implements ICPPEnumeration, ICPPInternalBinding { private static final IASTName NOT_INITIALIZED = CPPASTName.NOT_INITIALIZED; private static final IEnumerator[] EMPTY_ENUMERATORS = {}; public static class CPPEnumerationProblem extends ProblemBinding implements ICPPEnumeration, ICPPScope { public CPPEnumerationProblem(IASTNode node, int id, char[] arg) { super(node, id, arg); } @Override public IEnumerator[] getEnumerators() { return EMPTY_ENUMERATORS; } @Override public long getMinValue() { return 0; } @Override public long getMaxValue() { return 0; } @Override public boolean isScoped() { return false; } @Override public IType getFixedType() { return null; } @Override public ICPPScope asScope() { return this; } } private final boolean fIsScoped; private final IType fFixedType; private IASTName fDefinition= NOT_INITIALIZED; private IASTName[] fDeclarations= IASTName.EMPTY_NAME_ARRAY; private Long fMaxValue; private Long fMinValue; private ICPPEnumeration fIndexBinding; private boolean fSearchedIndex; public CPPEnumeration(ICPPASTEnumerationSpecifier spec, IType fixedType) { final IASTName name = spec.getName(); fIsScoped= spec.isScoped(); fFixedType= fixedType; if (spec.isOpaque()) { addDeclaration(name); } else { addDefinition(name); } name.setBinding(this); } @Override public IASTNode[] getDeclarations() { fDeclarations= ArrayUtil.trim(fDeclarations); return fDeclarations; } private class FindDefinitionAction extends ASTVisitor { private char[] nameArray = CPPEnumeration.this.getNameCharArray(); { shouldVisitNames = true; shouldVisitDeclarations = true; shouldVisitDeclSpecifiers = true; shouldVisitDeclarators = true; } @Override public int visit(IASTName name) { if (name instanceof ICPPASTTemplateId || name instanceof ICPPASTQualifiedName) return PROCESS_SKIP; char[] c = name.getLookupKey(); final IASTNode parent = name.getParent(); if (parent instanceof ICPPASTEnumerationSpecifier && !((ICPPASTEnumerationSpecifier) parent).isOpaque() && CharArrayUtils.equals(c, nameArray)) { IBinding binding = name.resolveBinding(); if (binding == CPPEnumeration.this && getDefinition() == name) { return PROCESS_ABORT; } } return PROCESS_CONTINUE; } @Override public int visit(IASTDeclaration declaration) { if (declaration instanceof IASTSimpleDeclaration) return PROCESS_CONTINUE; return PROCESS_SKIP; } @Override public int visit(IASTDeclSpecifier declSpec) { return (declSpec instanceof ICPPASTEnumerationSpecifier) ? PROCESS_CONTINUE : PROCESS_SKIP; } @Override public int visit(IASTDeclarator declarator) { return PROCESS_SKIP; } } @Override public IASTName getDefinition() { if (fDefinition == NOT_INITIALIZED) return null; return fDefinition; } @Override public String getName() { return new String(getNameCharArray()); } @Override public char[] getNameCharArray() { return getADeclaration().getSimpleID(); } private IASTName getADeclaration() { if (fDefinition != null && fDefinition != NOT_INITIALIZED) return fDefinition; return fDeclarations[0]; } @Override public IScope getScope() { return CPPVisitor.getContainingScope(getADeclaration()); } @Override public Object clone() { throw new IllegalArgumentException("Enums must not be cloned"); //$NON-NLS-1$ } @Override public String[] getQualifiedName() { return CPPVisitor.getQualifiedName(this); } @Override public char[][] getQualifiedNameCharArray() { return CPPVisitor.getQualifiedNameCharArray(this); } @Override public boolean isGloballyQualified() throws DOMException { IScope scope = getScope(); while (scope != null) { if (scope instanceof ICPPBlockScope) return false; scope = scope.getParent(); } return true; } @Override public void addDefinition(IASTNode node) { assert fDefinition == null || fDefinition == NOT_INITIALIZED; fDefinition= (IASTName) node; } @Override public void addDeclaration(IASTNode node) { assert node instanceof IASTName; if (fDeclarations == null) { fDeclarations= new IASTName[] {(IASTName) node}; } else { fDeclarations= ArrayUtil.append(fDeclarations, (IASTName) node); } } @Override public boolean isSameType(IType type) { if (type == this) return true; if (type instanceof ITypedef || type instanceof IIndexBinding) return type.isSameType(this); return false; } @Override public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } @Override public IBinding getOwner() { return CPPVisitor.findDeclarationOwner(getADeclaration(), true); } @Override public String toString() { return getName(); } @Override public long getMinValue() { if (fMinValue != null) return fMinValue.longValue(); long minValue = SemanticUtil.computeMinValue(this); fMinValue= minValue; return minValue; } @Override public long getMaxValue() { if (fMaxValue != null) return fMaxValue.longValue(); long maxValue = SemanticUtil.computeMaxValue(this); fMaxValue= maxValue; return maxValue; } @Override public boolean isScoped() { return fIsScoped; } @Override public IType getFixedType() { return fFixedType; } @Override public IEnumerator[] getEnumerators() { findDefinition(); final IASTName definition = getDefinition(); if (definition == null) { ICPPEnumeration typeInIndex= getIndexBinding(); if (typeInIndex != null) { return typeInIndex.getEnumerators(); } return EMPTY_ENUMERATORS; } IASTEnumerator[] enums = ((IASTEnumerationSpecifier) definition.getParent()).getEnumerators(); IEnumerator[] bindings = new IEnumerator[enums.length]; for (int i = 0; i < enums.length; i++) { bindings[i] = (IEnumerator) enums[i].getName().resolveBinding(); } return bindings; } private ICPPEnumeration getIndexBinding() { if (!fSearchedIndex) { final IASTTranslationUnit translationUnit = getADeclaration().getTranslationUnit(); IIndex index= translationUnit.getIndex(); if (index != null) { fIndexBinding= (ICPPEnumeration) index.adaptBinding(this); } } return fIndexBinding; } @Override public ICPPScope asScope() { findDefinition(); IASTName def = getDefinition(); if (def == null) { ICPPEnumeration indexBinding= getIndexBinding(); if (indexBinding != null) { return indexBinding.asScope(); } def= getADeclaration(); } return ((ICPPASTEnumerationSpecifier) def.getParent()).getScope(); } private void findDefinition() { if (fDefinition == NOT_INITIALIZED) { FindDefinitionAction action = new FindDefinitionAction(); IASTNode node = CPPVisitor.getContainingBlockItem(getADeclaration()).getParent(); node.accept(action); } } }