blob: fb757d85f89b85b39f4a54035b31e279b59c90cf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
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.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
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.IFunction;
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.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
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);
}
} else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
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);
}
}
}
} else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
protected int rwInStructuredBinding(ICPPASTStructuredBindingDeclaration declaration) {
RefQualifier refQualifier = declaration.getRefQualifier();
if (refQualifier != null && !declaration.getDeclSpecifier().isConst()) {
return READ | WRITE;
} else {
return READ;
}
}
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, args[i], indirection);
} else if (funcCall instanceof IASTImplicitNameOwner) {
IASTImplicitName[] implicitNames = ((IASTImplicitNameOwner) funcCall).getImplicitNames();
if (implicitNames.length == 1) {
IASTImplicitName name = implicitNames[0];
IBinding binding = name.resolveBinding();
if (binding instanceof IFunction) {
return rwArgumentForFunctionCall(((IFunction) binding).getType(), i, args[i],
indirection);
}
}
}
}
break;
}
}
return READ | WRITE; // Fallback
}
private IType getArgumentType(IASTInitializerClause argument) {
if (argument instanceof ICPPASTInitializerClause) {
return ((ICPPASTInitializerClause) argument).getEvaluation().getType();
} else if (argument instanceof IASTExpression) {
return ((IASTExpression) argument).getExpressionType();
}
return null;
}
protected int rwArgumentForFunctionCall(IFunctionType type, int parameterIdx, IASTInitializerClause argument,
int indirection) {
IType[] ptypes = type.getParameterTypes();
IType parameterType = null;
if (ptypes != null && ptypes.length > parameterIdx) {
parameterType = ptypes[parameterIdx];
} else if (type.takesVarArgs()) {
// Since variadic functions take their arguments by value, synthesize a parameter type
// equal to the argument type.
parameterType = getArgumentType(argument);
}
if (parameterType != null) {
return rwAssignmentToType(parameterType, 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
}
}