/******************************************************************************* * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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: * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCaseStatement; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTDoStatement; import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionList; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTFieldReference; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTInitializerList; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTProblemExpression; import org.eclipse.cdt.core.dom.ast.IASTProblemStatement; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression; import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; /** * Helper class to determine whether a variable is accessed for reading and/or writing. * The algorithm works starting from the variable and looking upwards what's being done * with the variable. C- and C++ specific things are handled in sub-classes. */ public abstract class VariableReadWriteFlags { protected static final int READ = PDOMName.READ_ACCESS; protected static final int WRITE = PDOMName.WRITE_ACCESS; protected int rwAnyNode(IASTNode node, int indirection) { final IASTNode parent = node.getParent(); if (parent instanceof IASTExpression) { return rwInExpression((IASTExpression) parent, node, indirection); } else if (parent instanceof IASTStatement) { return rwInStatement((IASTStatement) parent, node, indirection); } else if (parent instanceof IASTDeclarator) { return rwInDeclarator((IASTDeclarator) parent, indirection); } else if (parent instanceof IASTEqualsInitializer) { return rwInEqualsInitializer((IASTEqualsInitializer) parent, indirection); } else if (parent instanceof IASTArrayModifier) { return READ; // dimension } else if (parent instanceof IASTInitializerList) { return rwInInitializerList((IASTInitializerList) parent, indirection); } return READ | WRITE; // fallback } protected int rwInDeclarator(IASTDeclarator parent, int indirection) { if (parent.getInitializer() != null) return WRITE; return 0; } protected int rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) { IASTNode grand= parent.getParent(); if (grand instanceof IASTDeclarator) { IBinding binding= ((IASTDeclarator) grand).getName().getBinding(); if (binding instanceof IVariable) { return rwAssignmentToType(((IVariable) binding).getType(), indirection); } } return READ | WRITE; // fallback } protected int rwInInitializerList(IASTInitializerList parent, int indirection) { IASTNode grand= parent.getParent(); if (grand instanceof IASTEqualsInitializer) { IASTNode grandGrand= grand.getParent(); if (grandGrand instanceof IASTDeclarator) { IBinding binding= ((IASTDeclarator) grandGrand).getName().resolveBinding(); if (binding instanceof IVariable) { IType type= ((IVariable) binding).getType(); if (type instanceof IArrayType) { return rwAssignmentToType(type, indirection); } } } } return READ | WRITE; // fallback } protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) { if (expr instanceof IASTIdExpression) { return rwAnyNode(expr, indirection); } if (expr instanceof IASTBinaryExpression) { return rwInBinaryExpression(node, (IASTBinaryExpression) expr, indirection); } if (expr instanceof IASTFieldReference) { return rwInFieldReference(node, (IASTFieldReference) expr, indirection); } if (expr instanceof IASTCastExpression) { // must be ahead of unary return rwAnyNode(expr, indirection); } if (expr instanceof IASTUnaryExpression) { return rwInUnaryExpression(node, (IASTUnaryExpression) expr, indirection); } if (expr instanceof IASTArraySubscriptExpression) { if (indirection > 0 && node.getPropertyInParent() == IASTArraySubscriptExpression.ARRAY) { return rwAnyNode(expr, indirection - 1); } return READ; } if (expr instanceof IASTConditionalExpression) { if (node.getPropertyInParent() == IASTConditionalExpression.LOGICAL_CONDITION) { return READ; } return rwAnyNode(expr, indirection); } if (expr instanceof IASTExpressionList) { // Only the first expression is passed on. final IASTExpression[] expressions = ((IASTExpressionList) expr).getExpressions(); if (expressions.length > 0 && expressions[0] == node) { return rwAnyNode(expr, indirection); } return 0; } if (expr instanceof IASTFunctionCallExpression) { if (node.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { return rwInFunctionName((IASTExpression) node); } return rwArgumentForFunctionCall((IASTFunctionCallExpression) expr, node, indirection); } if (expr instanceof IASTProblemExpression) { return READ | WRITE; } if (expr instanceof IASTTypeIdExpression) { return 0; } return READ | WRITE; // fall back } protected int rwInFieldReference(IASTNode node, IASTFieldReference expr, int indirection) { if (node.getPropertyInParent() == IASTFieldReference.FIELD_NAME) { if (expr.getPropertyInParent() != IASTFunctionCallExpression.FUNCTION_NAME) return rwAnyNode(expr, indirection); } else { // IASTFieldReference.FIELD_OWNER if (expr.isPointerDereference()) --indirection; if (indirection >= 0) return rwAnyNode(expr, indirection); } return READ; } protected int rwInFunctionName(IASTExpression node) { return READ; } protected int rwArgumentForFunctionCall(final IASTFunctionCallExpression funcCall, IASTNode argument, int indirection) { final IASTInitializerClause[] args = funcCall.getArguments(); for (int i = 0; i < args.length; i++) { if (args[i] == argument) { final IASTExpression functionNameExpression = funcCall.getFunctionNameExpression(); if (functionNameExpression != null) { final IType type= functionNameExpression.getExpressionType(); if (type instanceof IFunctionType) { return rwArgumentForFunctionCall((IFunctionType) type, i, indirection); } } break; } } return READ | WRITE; // fallback } protected int rwArgumentForFunctionCall(IFunctionType type, int parameterIdx, int indirection) { IType[] ptypes= type.getParameterTypes(); if (ptypes != null && ptypes.length > parameterIdx) { return rwAssignmentToType(ptypes[parameterIdx], indirection); } return READ | WRITE; // Fallback } protected abstract int rwAssignmentToType(IType type, int indirection); protected int rwInStatement(IASTStatement stmt, IASTNode node, int indirection) { if (stmt instanceof IASTCaseStatement) { if (node.getPropertyInParent() == IASTCaseStatement.EXPRESSION) { return READ; } } else if (stmt instanceof IASTDoStatement) { if (node.getPropertyInParent() == IASTDoStatement.CONDITION) { return READ; } } else if (stmt instanceof IASTExpressionStatement) { IASTNode parent= stmt.getParent(); while (parent instanceof IASTCompoundStatement) { IASTCompoundStatement compound= (IASTCompoundStatement) parent; IASTStatement[] statements= compound.getStatements(); if (statements[statements.length - 1] != stmt) { return 0; } stmt= compound; parent= stmt.getParent(); } if (parent instanceof IGNUASTCompoundStatementExpression) { return rwAnyNode(parent, indirection); } } else if (stmt instanceof IASTForStatement) { if (node.getPropertyInParent() == IASTForStatement.CONDITION) { return READ; } } else if (stmt instanceof ICPPASTRangeBasedForStatement) { if (node.getPropertyInParent() == ICPPASTRangeBasedForStatement.INITIALIZER) { return READ; } } else if (stmt instanceof IASTIfStatement) { if (node.getPropertyInParent() == IASTIfStatement.CONDITION) { return READ; } } else if (stmt instanceof IASTProblemStatement) { return READ | WRITE; } else if (stmt instanceof IASTReturnStatement) { return indirection == 0 ? READ : WRITE; } else if (stmt instanceof IASTSwitchStatement) { if (node.getPropertyInParent() == IASTSwitchStatement.CONTROLLER_EXP) { return READ; } } else if (stmt instanceof IASTWhileStatement) { if (node.getPropertyInParent() == IASTWhileStatement.CONDITIONEXPRESSION) { return READ; } } return 0; } protected int rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) { switch(expr.getOperator()) { case IASTUnaryExpression.op_bracketedPrimary: return rwAnyNode(expr, indirection); case IASTUnaryExpression.op_amper: return rwAnyNode(expr, indirection + 1); case IASTUnaryExpression.op_star: if (indirection > 0) { return rwAnyNode(expr, indirection - 1); } return READ; case IASTUnaryExpression.op_postFixDecr: case IASTUnaryExpression.op_postFixIncr: case IASTUnaryExpression.op_prefixDecr: case IASTUnaryExpression.op_prefixIncr: return READ | WRITE; case IASTUnaryExpression.op_minus: case IASTUnaryExpression.op_not: case IASTUnaryExpression.op_plus: case IASTUnaryExpression.op_tilde: return PDOMName.READ_ACCESS; case IASTUnaryExpression.op_sizeof: case IASTUnaryExpression.op_sizeofParameterPack: case IASTUnaryExpression.op_alignOf: return 0; } return READ; } protected int rwInBinaryExpression(IASTNode node, IASTBinaryExpression expr, int indirection) { switch(expr.getOperator()) { case IASTBinaryExpression.op_assign: if (node.getPropertyInParent() == IASTBinaryExpression.OPERAND_ONE) { return WRITE; } return rwAssignmentToType(expr.getOperand1().getExpressionType(), indirection); case IASTBinaryExpression.op_binaryAndAssign: case IASTBinaryExpression.op_binaryOrAssign: case IASTBinaryExpression.op_binaryXorAssign: case IASTBinaryExpression.op_divideAssign: case IASTBinaryExpression.op_minusAssign: case IASTBinaryExpression.op_moduloAssign: case IASTBinaryExpression.op_multiplyAssign: case IASTBinaryExpression.op_plusAssign: case IASTBinaryExpression.op_shiftLeftAssign: case IASTBinaryExpression.op_shiftRightAssign: if (node.getPropertyInParent() == IASTBinaryExpression.OPERAND_ONE) { return READ | WRITE; } return READ; case IASTBinaryExpression.op_binaryAnd: case IASTBinaryExpression.op_binaryOr: case IASTBinaryExpression.op_binaryXor: case IASTBinaryExpression.op_divide: case IASTBinaryExpression.op_equals: case IASTBinaryExpression.op_greaterEqual: case IASTBinaryExpression.op_greaterThan: case IASTBinaryExpression.op_lessEqual: case IASTBinaryExpression.op_lessThan: case IASTBinaryExpression.op_logicalAnd: case IASTBinaryExpression.op_logicalOr: case IASTBinaryExpression.op_modulo: case IASTBinaryExpression.op_multiply: case IASTBinaryExpression.op_notequals: case IASTBinaryExpression.op_shiftLeft: case IASTBinaryExpression.op_shiftRight: return READ; case IASTBinaryExpression.op_minus: case IASTBinaryExpression.op_plus: if (indirection > 0) { // can be pointer arithmetics return rwAnyNode(expr, indirection); } return READ; } return READ; // fallback } }