/******************************************************************************* * Copyright (c) 2015, 2016 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences. * 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: * Lukas Wegmann (IFS) - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; 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.IASTInitializer; 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.IArrayType; 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.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; /** * Collects functionality used by CPPVariable, CPPVariableTemplate and their subclasses. */ public class VariableHelpers { public static boolean hasStorageClass(IASTName name, IASTNode[] declarations, int storage) { int i = -1; do { if (name != null) { IASTNode parent = name.getParent(); while (!(parent instanceof IASTDeclaration)) parent = parent.getParent(); if (parent instanceof IASTSimpleDeclaration) { IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); if (declSpec.getStorageClass() == storage) { return true; } } } if (declarations != null && ++i < declarations.length) { name = (IASTName) declarations[i]; } else { break; } } while (name != null); return false; } public static boolean isConstexpr(IASTName definition) { if (definition == null) return false; IASTNode parent = definition.getParent(); while (!(parent instanceof IASTDeclaration)) { parent = parent.getParent(); } if (parent instanceof IASTSimpleDeclaration) { ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) parent).getDeclSpecifier(); if (declSpec != null) return declSpec.isConstexpr(); } return false; } @SuppressWarnings("null") public static IType createType(ICPPVariable variable, IASTName definition, IASTName[] declarations, boolean allDeclarationsResolved) { boolean doneWithDefinition = false; IArrayType firstCandidate = null; final int length = declarations == null ? 0 : declarations.length; for (int i = 0; i <= length; i++) { IASTName n; // Process the definition according to its relative position among // the declarations. // See http://bugs.eclipse.org/434150 if (definition != null && !doneWithDefinition && (i == length || ((ASTNode) definition).getOffset() < ((ASTNode) declarations[i]).getOffset())) { n = definition; doneWithDefinition = true; --i; // We still have to come back to the declaration at position i. } else if (i < length) { n = declarations[i]; } else { break; } if (n != null) { while (n.getParent() instanceof IASTName) { n = (IASTName) n.getParent(); } IASTNode node = n.getParent(); if (node instanceof IASTDeclarator) { IType t = CPPVisitor.createType((IASTDeclarator) node); if (!(t instanceof IArrayType) || ((IArrayType) t).hasSize()) { return t; } if (firstCandidate == null) { firstCandidate = (IArrayType) t; } } } } if (!allDeclarationsResolved) { resolveAllDeclarations(variable, definition, declarations); return variable.getType(); } return firstCandidate; } private static void resolveAllDeclarations(ICPPVariable variable, IASTName definition, IASTName[] declarations) { final int length = declarations == null ? 0 : declarations.length; for (int i = -1; i < length; i++) { @SuppressWarnings("null") IASTName n = i == -1 ? definition : declarations[i]; if (n != null) { IASTTranslationUnit tu = n.getTranslationUnit(); if (tu != null) { CPPVisitor.getDeclarations(tu, variable); return; } } } } public static IValue getInitialValue(IASTName definition, IASTName[] declarations, IType type) { if (definition != null) { final IValue val = getInitialValue(definition, type); if (val != null) return val; } if (declarations != null) { for (IASTName decl : declarations) { if (decl == null) break; final IValue val = getInitialValue(decl, type); if (val != null) return val; } } return null; } private static IValue getInitialValue(IASTName name, IType type) { IASTDeclarator dtor = findDeclarator(name); if (dtor != null) { IASTInitializer init = dtor.getInitializer(); if (init != null) { return SemanticUtil.getValueOfInitializer(init, type); } } return null; } public static IASTDeclarator findDeclarator(IASTName name) { IASTNode node = name.getParent(); if (node instanceof ICPPASTQualifiedName) node = node.getParent(); if (!(node instanceof IASTDeclarator)) return null; IASTDeclarator dtor = (IASTDeclarator) node; while (dtor.getParent() instanceof IASTDeclarator) { dtor = (IASTDeclarator) dtor.getParent(); } return dtor; } public static int getVisibility(ICPPInternalVariable field) { ICPPASTVisibilityLabel vis = null; IASTDeclaration decl = getPrimaryDeclaration(field); if (decl != null) { IASTCompositeTypeSpecifier cls = (IASTCompositeTypeSpecifier) decl.getParent(); IASTDeclaration[] members = cls.getMembers(); for (IASTDeclaration member : members) { if (member == decl) break; if (member instanceof ICPPASTVisibilityLabel) vis = (ICPPASTVisibilityLabel) member; } if (vis != null) { return vis.getVisibility(); } else if (cls.getKey() == ICPPASTCompositeTypeSpecifier.k_class) { return ICPPASTVisibilityLabel.v_private; } } return ICPPASTVisibilityLabel.v_public; } private static IASTDeclaration getPrimaryDeclaration(ICPPInternalVariable field) { // First check if we already know it. IASTDeclaration decl= findDeclaration(field.getDefinition()); if (decl != null) { return decl; } IASTName[] declarations = (IASTName[]) field.getDeclarations(); if (declarations != null) { for (IASTName name : declarations) { decl= findDeclaration(name); if (decl != null) { return decl; } } } char[] myName = field.getNameCharArray(); ICPPClassScope scope = findClassScope(field); ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) ASTInternal.getPhysicalNodeOfScope(scope); IASTDeclaration[] members = compSpec.getMembers(); for (IASTDeclaration member : members) { if (member instanceof IASTSimpleDeclaration) { IASTDeclarator[] dtors = ((IASTSimpleDeclaration) member).getDeclarators(); for (IASTDeclarator dtor : dtors) { IASTName name = dtor.getName(); if (CharArrayUtils.equals(name.getLookupKey(), myName) && name.resolveBinding() == field) { return member; } } } } return null; } private static ICPPClassScope findClassScope(ICPPInternalVariable v) { IScope scope; try { scope = v.getScope(); } catch (DOMException e) { scope = null; } while (scope != null) { if (scope instanceof ICPPClassScope) { return (ICPPClassScope) scope; } try { scope = scope.getParent(); } catch (DOMException e) { return null; } } return null; } private static IASTDeclaration findDeclaration(IASTNode node) { while (node != null && !(node instanceof IASTDeclaration)) { node = node.getParent(); } if (node != null && node.getParent() instanceof ICPPASTCompositeTypeSpecifier) { return (IASTDeclaration) node; } return null; } }