/******************************************************************************* * Copyright (c) 2004, 2016 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) * Ed Swartz (Nokia) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IArrayType; 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.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.parser.util.ArrayUtil; 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.DependentValue; import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.core.runtime.PlatformObject; public class CPPVariable extends PlatformObject implements ICPPInternalVariable { private IASTName fDefinition; private IASTName fDeclarations[]; private IType fType; private boolean fAllResolved; public CPPVariable(IASTName name) { boolean isDef = name != null && name.isDefinition(); if (name instanceof ICPPASTQualifiedName) { name = name.getLastName(); } if (isDef) { fDefinition = name; } else { fDeclarations = new IASTName[] { name }; } // Built-in variables supply a null. if (name != null) { name.setBinding(this); } else { assert this instanceof CPPBuiltinVariable; } } @Override public void addDeclaration(IASTNode node) { if (!(node instanceof IASTName)) return; IASTName name = (IASTName) node; if (fDefinition == null && name.isDefinition()) { fDefinition = name; } else if (fDeclarations == null) { fDeclarations = new IASTName[] { name }; } else { // Keep the lowest offset declaration at the first position. if (fDeclarations.length > 0 && ((ASTNode) node).getOffset() < ((ASTNode) fDeclarations[0]).getOffset()) { fDeclarations = ArrayUtil.prepend(IASTName.class, fDeclarations, name); } else { fDeclarations = ArrayUtil.append(IASTName.class, fDeclarations, name); } } // Array types may be incomplete. if (fType instanceof IArrayType) { fType = null; } } @Override public IASTNode[] getDeclarations() { return fDeclarations; } @Override public IASTNode getDefinition() { return fDefinition; } @Override public IType getType() { if (fType != null) { return fType; } boolean allResolved = fAllResolved; fAllResolved = true; fType = VariableHelpers.createType(this, fDefinition, fDeclarations, allResolved); return fType; } @Override public String getName() { return new String(getNameCharArray()); } @Override public char[] getNameCharArray() { if (fDeclarations != null) { return fDeclarations[0].getSimpleID(); } return fDefinition.getSimpleID(); } @Override public IScope getScope() { return CPPVisitor.getContainingScope(fDefinition != null ? fDefinition : fDeclarations[0]); } @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) { addDeclaration(node); } public boolean hasStorageClass(int storage) { IASTName name = (IASTName) getDefinition(); IASTNode[] ns = getDeclarations(); return VariableHelpers.hasStorageClass(name, ns, storage); } @Override public boolean isMutable() { // 7.1.1-8 the mutable specifier can only be applied to names of class data members. return false; } @Override public boolean isConstexpr() { return VariableHelpers.isConstexpr(fDefinition); } @Override public boolean isStatic() { return hasStorageClass(IASTDeclSpecifier.sc_static); } @Override public boolean isExtern() { return hasStorageClass(IASTDeclSpecifier.sc_extern); } @Override public boolean isExternC() { return CPPVisitor.isExternC(getDefinition(), getDeclarations()); } @Override public boolean isAuto() { return hasStorageClass(IASTDeclSpecifier.sc_auto); } @Override public boolean isRegister() { return hasStorageClass(IASTDeclSpecifier.sc_register); } @Override public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } @Override public IBinding getOwner() { IASTName node = fDefinition != null ? fDefinition : fDeclarations[0]; return CPPVisitor.findNameOwner(node, !hasStorageClass(IASTDeclSpecifier.sc_extern)); } @Override public IValue getInitialValue() { IValue initialValue = null; final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE); if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition, fDeclarations, getType())) == IntegralValue.UNKNOWN) { ICPPEvaluation initEval = getInitializerEvaluation(); if (initEval == null) { return null; } if (!initEval.isValueDependent() ) { return initEval.getValue(fDefinition); } return DependentValue.create(initEval); } return initialValue; } private IASTDeclarator findDeclarator() { IASTDeclarator declarator = null; if (fDefinition != null) { declarator = VariableHelpers.findDeclarator(fDefinition); if (declarator != null) { return declarator; } } if (fDeclarations != null) { for (IASTName decl : fDeclarations) { if (decl == null) break; declarator = VariableHelpers.findDeclarator(decl); if (declarator != null) { return declarator; } } } return null; } @Override public String toString() { return getName(); } /** * Returns an evaluation representing the variable's initialization. * * If the variable has no initializer, {@code null} is returned. */ public ICPPEvaluation getInitializerEvaluation() { ICPPASTDeclarator declarator = (ICPPASTDeclarator) findDeclarator(); if (declarator != null) { IASTInitializer initializer = declarator.getInitializer(); ICPPConstructor constructor = getImplicitlyCalledCtor(declarator); if (constructor != null) { ICPPEvaluation[] arguments = EvalConstructor.extractArguments(initializer, constructor); return new EvalConstructor(getType(), constructor, arguments, declarator); } else if (initializer instanceof IASTEqualsInitializer) { IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer; ICPPEvaluationOwner evalOwner = (ICPPEvaluationOwner) equalsInitializer.getInitializerClause(); return evalOwner.getEvaluation(); } else if (initializer instanceof ICPPASTInitializerList) { ICPPEvaluationOwner evalOwner = (ICPPEvaluationOwner) initializer; return evalOwner.getEvaluation(); } else if (initializer instanceof ICPPASTConstructorInitializer) { ICPPASTConstructorInitializer ctorInitializer = (ICPPASTConstructorInitializer) initializer; ICPPEvaluationOwner evalOwner = (ICPPEvaluationOwner) ctorInitializer.getArguments()[0]; return evalOwner.getEvaluation(); } else if (initializer == null) { return null; } } return EvalFixed.INCOMPLETE; } private static ICPPConstructor getImplicitlyCalledCtor(ICPPASTDeclarator declarator) { IBinding ctor = CPPSemantics.findImplicitlyCalledConstructor(declarator); if (ctor instanceof ICPPConstructor && !EvalUtil.isCompilerGeneratedCtor(ctor)) { return (ICPPConstructor) ctor; } return null; } }