1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 01:15:29 +02:00

Bug 561088 - Fix read/write flags in case of dependent types

Change-Id: I072bb53a95d17137eb614bff34de6bd57a371d33
This commit is contained in:
Marco Stornelli 2020-03-13 09:04:11 +01:00
parent c69bec4979
commit 7a833fbb50
11 changed files with 301 additions and 118 deletions

View file

@ -17,6 +17,7 @@
package org.eclipse.cdt.codan.internal.checkers;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.Stack;
@ -59,7 +60,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
/**
* Checks that class members of simple types (int, float, pointers,
@ -212,7 +212,8 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
IField equivalentFieldBinding = getContainedEquivalentBinding(actualConstructorFields, binding,
name.getTranslationUnit().getIndex());
if (equivalentFieldBinding != null) {
if ((CPPVariableReadWriteFlags.getReadWriteFlags(name) & PDOMName.WRITE_ACCESS) != 0) {
Optional<Integer> res = CPPVariableReadWriteFlags.getReadWriteFlags(name);
if (CPPVariableReadWriteFlags.mayBeWriteAccess(res)) {
actualConstructorFields.remove(equivalentFieldBinding);
}
}

View file

@ -14,6 +14,7 @@
package org.eclipse.cdt.core.parser.tests.ast2;
import java.io.IOException;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.internal.core.dom.parser.c.CVariableReadWriteFlags;
@ -35,27 +36,34 @@ public class VariableReadWriteFlagsTest extends AST2TestBase {
super(contents, isCPP);
}
void assertReadWriteFlags(String context, String name, int expectedFlags) throws Exception {
void assertReadWriteFlags(String context, String name, Optional<Integer> expectedFlags) throws Exception {
IASTName variable = findName(context, name);
assertNotNull(variable);
assertEquals(flagsToString(expectedFlags), flagsToString(getReadWriteFlags(variable)));
}
void assertReadWriteFlags(String name, int expectedFlags) throws Exception {
assertReadWriteFlags(null, name, expectedFlags);
void assertReadWriteFlags(String context, String name, int expectedFlags) throws Exception {
assertReadWriteFlags(context, name, Optional.of(expectedFlags));
}
int getReadWriteFlags(IASTName variable) {
void assertReadWriteFlags(String context, String name) throws Exception {
assertReadWriteFlags(context, name, Optional.empty());
}
Optional<Integer> getReadWriteFlags(IASTName variable) {
return isCPP ? CPPVariableReadWriteFlags.getReadWriteFlags(variable)
: CVariableReadWriteFlags.getReadWriteFlags(variable);
}
private String flagsToString(int flags) {
private String flagsToString(Optional<Integer> flags) {
StringBuilder buf = new StringBuilder();
if ((flags & READ) != 0) {
if (!flags.isPresent()) {
buf.append("UNK");
}
if (flags.isPresent() && (flags.get() & READ) != 0) {
buf.append("READ");
}
if ((flags & WRITE) != 0) {
if (flags.isPresent() && (flags.get() & WRITE) != 0) {
if (buf.length() != 0)
buf.append(" | ");
buf.append("WRITE");
@ -153,8 +161,8 @@ public class VariableReadWriteFlagsTest extends AST2TestBase {
// };
public void testFunctionCall() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("f(&a, b)", "a", READ | WRITE);
a.assertReadWriteFlags("f(&a, b)", "b", READ | WRITE);
a.assertReadWriteFlags("f(&a, b)", "a");
a.assertReadWriteFlags("f(&a, b)", "b");
a.assertReadWriteFlags("f(&a, b)", "f", READ);
a.assertReadWriteFlags("g(&a, b, c)", "a", READ);
a.assertReadWriteFlags("g(&a, b, c)", "b", READ);
@ -176,12 +184,12 @@ public class VariableReadWriteFlagsTest extends AST2TestBase {
// };
public void testConstructorCall_393068() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("= A(&a, b)", "a", READ | WRITE);
a.assertReadWriteFlags("= A(&a, b)", "b", READ | WRITE);
a.assertReadWriteFlags("new A(&a, b)", "a", READ | WRITE);
a.assertReadWriteFlags("new A(&a, b)", "b", READ | WRITE);
a.assertReadWriteFlags("w(&a, b)", "a", READ | WRITE);
a.assertReadWriteFlags("w(&a, b)", "b", READ | WRITE);
a.assertReadWriteFlags("= A(&a, b)", "a");
a.assertReadWriteFlags("= A(&a, b)", "b");
a.assertReadWriteFlags("new A(&a, b)", "a");
a.assertReadWriteFlags("new A(&a, b)", "b");
a.assertReadWriteFlags("w(&a, b)", "a");
a.assertReadWriteFlags("w(&a, b)", "b");
a.assertReadWriteFlags("w(&a, b)", "w", WRITE);
a.assertReadWriteFlags("= A(&a, b, c)", "a", READ);
a.assertReadWriteFlags("= A(&a, b, c)", "b", READ);
@ -227,7 +235,7 @@ public class VariableReadWriteFlagsTest extends AST2TestBase {
public void testVariadicFunctionCall_452416() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("variadic(waldo)", "waldo", READ);
a.assertReadWriteFlags("variadic(&waldo)", "waldo", READ | WRITE);
a.assertReadWriteFlags("variadic(&waldo)", "waldo");
}
// int arr[5];
@ -257,4 +265,20 @@ public class VariableReadWriteFlagsTest extends AST2TestBase {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("decltype(v) o = 14;", "v", READ);
}
//template <typename S, typename T>
//void g(S, T);
//
//struct A {
// int field;
//
// template <typename S>
// void method3(S s) const {
// g(s, field);
// }
//};
public void testDependentType() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("g(s, field);", "field");
}
}

View file

@ -14,6 +14,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
@ -68,7 +70,19 @@ 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) {
/**
* Check if the access could be a write access taking into
* account the "unknown" state.
* @param flags The flags
* @return True if either write or unknown access detected, false otherwise
*/
public static boolean mayBeWriteAccess(Optional<Integer> flags) {
if (!flags.isPresent() || (flags.get() & WRITE) != 0)
return true;
return false;
}
protected Optional<Integer> rwAnyNode(IASTNode node, int indirection) {
final IASTNode parent = node.getParent();
if (parent instanceof IASTExpression) {
return rwInExpression((IASTExpression) parent, node, indirection);
@ -79,22 +93,22 @@ public abstract class VariableReadWriteFlags {
} else if (parent instanceof IASTEqualsInitializer) {
return rwInEqualsInitializer((IASTEqualsInitializer) parent, indirection);
} else if (parent instanceof IASTArrayModifier) {
return READ; // dimension
return Optional.of(READ); // dimension
} else if (parent instanceof IASTInitializerList) {
return rwInInitializerList((IASTInitializerList) parent, indirection);
} else if (parent instanceof IASTDeclSpecifier) {
return READ;
return Optional.of(READ);
}
return READ | WRITE; // fallback
return Optional.empty(); // fallback
}
protected int rwInDeclarator(IASTDeclarator parent, int indirection) {
protected Optional<Integer> rwInDeclarator(IASTDeclarator parent, int indirection) {
if (parent.getInitializer() != null)
return WRITE;
return 0;
return Optional.of(WRITE);
return Optional.of(0);
}
protected int rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) {
protected Optional<Integer> rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) {
IASTNode grand = parent.getParent();
if (grand instanceof IASTDeclarator) {
IBinding binding = ((IASTDeclarator) grand).getName().getBinding();
@ -104,10 +118,10 @@ public abstract class VariableReadWriteFlags {
} else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
return Optional.empty(); // fallback
}
protected int rwInInitializerList(IASTInitializerList parent, int indirection) {
protected Optional<Integer> rwInInitializerList(IASTInitializerList parent, int indirection) {
IASTNode grand = parent.getParent();
if (grand instanceof IASTEqualsInitializer) {
IASTNode grandGrand = grand.getParent();
@ -123,15 +137,15 @@ public abstract class VariableReadWriteFlags {
} else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
return Optional.empty(); // fallback
}
protected int rwInStructuredBinding(ICPPASTStructuredBindingDeclaration declaration) {
protected Optional<Integer> rwInStructuredBinding(ICPPASTStructuredBindingDeclaration declaration) {
RefQualifier refQualifier = declaration.getRefQualifier();
if (refQualifier != null && !declaration.getDeclSpecifier().isConst()) {
return READ | WRITE;
return Optional.of(READ | WRITE);
} else {
return READ;
return Optional.of(READ);
}
}
@ -153,7 +167,7 @@ public abstract class VariableReadWriteFlags {
return false;
}
protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
protected Optional<Integer> rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
if (expr instanceof IASTIdExpression) {
return rwAnyNode(expr, indirection);
}
@ -176,13 +190,13 @@ public abstract class VariableReadWriteFlags {
if (expr.getParent() instanceof IASTBinaryExpression
&& expr.getPropertyInParent() == IASTBinaryExpression.OPERAND_ONE
&& isAssignment((IASTBinaryExpression) expr.getParent())) {
return READ | WRITE;
return Optional.of(READ | WRITE);
}
return READ;
return Optional.of(READ);
}
if (expr instanceof IASTConditionalExpression) {
if (node.getPropertyInParent() == IASTConditionalExpression.LOGICAL_CONDITION) {
return READ;
return Optional.of(READ);
}
return rwAnyNode(expr, indirection);
}
@ -192,7 +206,7 @@ public abstract class VariableReadWriteFlags {
if (expressions.length > 0 && expressions[0] == node) {
return rwAnyNode(expr, indirection);
}
return 0;
return Optional.of(0);
}
if (expr instanceof IASTFunctionCallExpression) {
if (node.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
@ -201,16 +215,16 @@ public abstract class VariableReadWriteFlags {
return rwArgumentForFunctionCall((IASTFunctionCallExpression) expr, node, indirection);
}
if (expr instanceof IASTProblemExpression) {
return READ | WRITE;
return Optional.of(READ | WRITE);
}
if (expr instanceof IASTTypeIdExpression) {
return 0;
return Optional.of(0);
}
return READ | WRITE; // fall back
return Optional.empty(); // fall back
}
protected int rwInFieldReference(IASTNode node, IASTFieldReference expr, int indirection) {
protected Optional<Integer> rwInFieldReference(IASTNode node, IASTFieldReference expr, int indirection) {
if (node.getPropertyInParent() == IASTFieldReference.FIELD_NAME) {
if (expr.getPropertyInParent() != IASTFunctionCallExpression.FUNCTION_NAME)
return rwAnyNode(expr, indirection);
@ -220,22 +234,70 @@ public abstract class VariableReadWriteFlags {
if (indirection >= 0)
return rwAnyNode(expr, indirection);
}
return READ;
return Optional.of(READ);
}
protected int rwInFunctionName(IASTExpression node) {
return READ;
protected Optional<Integer> rwInFunctionName(IASTExpression node) {
return Optional.of(READ);
}
protected int rwArgumentForFunctionCall(final IASTFunctionCallExpression funcCall, IASTNode argument,
/**
* Check if the function name expression involves a deferred function. Applicable
* only to C++.
* @param functionNameExpression The expression
* @return The binding found, null otherwise
*/
protected abstract IBinding getDeferredFunction(IASTExpression functionNameExpression);
/**
* Evaluate the deferred function and check the flags for arguments passed. Applicable
* only to C++.
* @param funcCall The function call expression
* @param arg The argument to be evaluated
* @param argPos The argument position
* @param indirection Level of indirection
* @param defFunctionBinding The function binding
* @return Access flags
*/
protected abstract Optional<Integer> evaluateDeferredFunction(final IASTFunctionCallExpression funcCall,
final IASTInitializerClause arg, int argPos, int indirection, IBinding defFunctionBinding);
/**
* Helper method to merge two optional flags containers
* @param a A flag optional container
* @param b A flag optional container
* @return An optional with bit or operation between a and b
*/
protected Optional<Integer> bitwiseOr(Optional<Integer> a, Optional<Integer> b) {
Optional<Integer> or = Optional.empty();
if (a.isPresent()) {
if (!b.isPresent()) {
or = a;
} else {
or = Optional.of(a.get() | b.get());
}
} else {
if (!b.isPresent()) {
return or;
} else {
or = b;
}
}
return or;
}
protected Optional<Integer> 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) {
IType type = functionNameExpression.getExpressionType();
IBinding deferredFunc = getDeferredFunction(functionNameExpression);
if (deferredFunc != null) {
return evaluateDeferredFunction(funcCall, args[i], i, indirection, deferredFunc);
} else if (type instanceof IFunctionType) {
return rwArgumentForFunctionCall((IFunctionType) type, i, args[i], indirection);
} else if (funcCall instanceof IASTImplicitNameOwner) {
IASTImplicitName[] implicitNames = ((IASTImplicitNameOwner) funcCall).getImplicitNames();
@ -252,7 +314,7 @@ public abstract class VariableReadWriteFlags {
break;
}
}
return READ | WRITE; // Fallback
return Optional.empty(); // Fallback
}
private IType getArgumentType(IASTInitializerClause argument) {
@ -264,8 +326,8 @@ public abstract class VariableReadWriteFlags {
return null;
}
protected int rwArgumentForFunctionCall(IFunctionType type, int parameterIdx, IASTInitializerClause argument,
int indirection) {
protected Optional<Integer> rwArgumentForFunctionCall(IFunctionType type, int parameterIdx,
IASTInitializerClause argument, int indirection) {
IType[] ptypes = type.getParameterTypes();
IType parameterType = null;
if (ptypes != null && ptypes.length > parameterIdx) {
@ -279,19 +341,19 @@ public abstract class VariableReadWriteFlags {
if (parameterType != null) {
return rwAssignmentToType(parameterType, indirection);
}
return READ | WRITE; // Fallback
return Optional.empty(); // Fallback
}
protected abstract int rwAssignmentToType(IType type, int indirection);
protected abstract Optional<Integer> rwAssignmentToType(IType type, int indirection);
protected int rwInStatement(IASTStatement stmt, IASTNode node, int indirection) {
protected Optional<Integer> rwInStatement(IASTStatement stmt, IASTNode node, int indirection) {
if (stmt instanceof IASTCaseStatement) {
if (node.getPropertyInParent() == IASTCaseStatement.EXPRESSION) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof IASTDoStatement) {
if (node.getPropertyInParent() == IASTDoStatement.CONDITION) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof IASTExpressionStatement) {
IASTNode parent = stmt.getParent();
@ -299,7 +361,7 @@ public abstract class VariableReadWriteFlags {
IASTCompoundStatement compound = (IASTCompoundStatement) parent;
IASTStatement[] statements = compound.getStatements();
if (statements[statements.length - 1] != stmt) {
return 0;
return Optional.of(0);
}
stmt = compound;
parent = stmt.getParent();
@ -309,33 +371,33 @@ public abstract class VariableReadWriteFlags {
}
} else if (stmt instanceof IASTForStatement) {
if (node.getPropertyInParent() == IASTForStatement.CONDITION) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof ICPPASTRangeBasedForStatement) {
if (node.getPropertyInParent() == ICPPASTRangeBasedForStatement.INITIALIZER) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof IASTIfStatement) {
if (node.getPropertyInParent() == IASTIfStatement.CONDITION) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof IASTProblemStatement) {
return READ | WRITE;
return Optional.empty();
} else if (stmt instanceof IASTReturnStatement) {
return indirection == 0 ? READ : WRITE;
return indirection == 0 ? Optional.of(READ) : Optional.of(WRITE);
} else if (stmt instanceof IASTSwitchStatement) {
if (node.getPropertyInParent() == IASTSwitchStatement.CONTROLLER_EXP) {
return READ;
return Optional.of(READ);
}
} else if (stmt instanceof IASTWhileStatement) {
if (node.getPropertyInParent() == IASTWhileStatement.CONDITIONEXPRESSION) {
return READ;
return Optional.of(READ);
}
}
return 0;
return Optional.of(0);
}
protected int rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) {
protected Optional<Integer> rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) {
switch (expr.getOperator()) {
case IASTUnaryExpression.op_bracketedPrimary:
return rwAnyNode(expr, indirection);
@ -347,33 +409,33 @@ public abstract class VariableReadWriteFlags {
if (indirection > 0) {
return rwAnyNode(expr, indirection - 1);
}
return READ;
return Optional.of(READ);
case IASTUnaryExpression.op_postFixDecr:
case IASTUnaryExpression.op_postFixIncr:
case IASTUnaryExpression.op_prefixDecr:
case IASTUnaryExpression.op_prefixIncr:
return READ | WRITE;
return Optional.of(READ | WRITE);
case IASTUnaryExpression.op_minus:
case IASTUnaryExpression.op_not:
case IASTUnaryExpression.op_plus:
case IASTUnaryExpression.op_tilde:
return PDOMName.READ_ACCESS;
return Optional.of(READ);
case IASTUnaryExpression.op_sizeof:
case IASTUnaryExpression.op_sizeofParameterPack:
case IASTUnaryExpression.op_alignOf:
return 0;
return Optional.of(0);
}
return READ;
return Optional.of(READ);
}
protected int rwInBinaryExpression(IASTNode node, IASTBinaryExpression expr, int indirection) {
protected Optional<Integer> rwInBinaryExpression(IASTNode node, IASTBinaryExpression expr, int indirection) {
switch (expr.getOperator()) {
case IASTBinaryExpression.op_assign:
if (node.getPropertyInParent() == IASTBinaryExpression.OPERAND_ONE) {
return WRITE;
return Optional.of(WRITE);
}
return rwAssignmentToType(expr.getOperand1().getExpressionType(), indirection);
@ -388,9 +450,9 @@ public abstract class VariableReadWriteFlags {
case IASTBinaryExpression.op_shiftLeftAssign:
case IASTBinaryExpression.op_shiftRightAssign:
if (node.getPropertyInParent() == IASTBinaryExpression.OPERAND_ONE) {
return READ | WRITE;
return Optional.of(READ | WRITE);
}
return READ;
return Optional.of(READ);
case IASTBinaryExpression.op_binaryAnd:
case IASTBinaryExpression.op_binaryOr:
@ -408,7 +470,7 @@ public abstract class VariableReadWriteFlags {
case IASTBinaryExpression.op_notequals:
case IASTBinaryExpression.op_shiftLeft:
case IASTBinaryExpression.op_shiftRight:
return READ;
return Optional.of(READ);
case IASTBinaryExpression.op_minus:
case IASTBinaryExpression.op_plus:
@ -416,8 +478,8 @@ public abstract class VariableReadWriteFlags {
// can be pointer arithmetics
return rwAnyNode(expr, indirection);
}
return READ;
return Optional.of(READ);
}
return READ; // fallback
return Optional.of(READ); // fallback
}
}

View file

@ -13,11 +13,15 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType;
@ -33,47 +37,48 @@ import org.eclipse.cdt.internal.core.dom.parser.VariableReadWriteFlags;
public final class CVariableReadWriteFlags extends VariableReadWriteFlags {
private static CVariableReadWriteFlags INSTANCE = new CVariableReadWriteFlags();
public static int getReadWriteFlags(IASTName variable) {
public static Optional<Integer> getReadWriteFlags(IASTName variable) {
return INSTANCE.rwAnyNode(variable, 0);
}
@Override
protected int rwAnyNode(IASTNode node, int indirection) {
protected Optional<Integer> rwAnyNode(IASTNode node, int indirection) {
final IASTNode parent = node.getParent();
if (parent instanceof ICASTFieldDesignator) {
return WRITE; // node is initialized via designated initializer
return Optional.of(WRITE); // node is initialized via designated initializer
}
return super.rwAnyNode(node, indirection);
}
@Override
protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
protected Optional<Integer> rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
if (expr instanceof ICASTTypeIdInitializerExpression) {
return 0;
return Optional.of(0);
}
return super.rwInExpression(expr, node, indirection);
}
@Override
protected int rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) {
protected Optional<Integer> rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) {
if (indirection == 0) {
return READ;
return Optional.of(READ);
}
return super.rwInEqualsInitializer(parent, indirection);
}
@Override
protected int rwArgumentForFunctionCall(IASTFunctionCallExpression funcCall, IASTNode argument, int indirection) {
protected Optional<Integer> rwArgumentForFunctionCall(IASTFunctionCallExpression funcCall, IASTNode argument,
int indirection) {
if (indirection == 0) {
return READ;
return Optional.of(READ);
}
return super.rwArgumentForFunctionCall(funcCall, argument, indirection);
}
@Override
protected int rwAssignmentToType(IType type, int indirection) {
protected Optional<Integer> rwAssignmentToType(IType type, int indirection) {
if (indirection == 0) {
return READ;
return Optional.of(READ);
}
while (indirection > 0 && (type instanceof IPointerType)) {
type = ((IPointerType) type).getType();
@ -81,11 +86,22 @@ public final class CVariableReadWriteFlags extends VariableReadWriteFlags {
}
if (indirection == 0) {
if (type instanceof IQualifierType) {
return ((IQualifierType) type).isConst() ? READ : READ | WRITE;
return ((IQualifierType) type).isConst() ? Optional.of(READ) : Optional.of(READ | WRITE);
} else if (type instanceof IPointerType) {
return ((IPointerType) type).isConst() ? READ : READ | WRITE;
return ((IPointerType) type).isConst() ? Optional.of(READ) : Optional.of(READ | WRITE);
}
}
return READ | WRITE; // fallback
return Optional.empty(); // Fallback
}
@Override
protected IBinding getDeferredFunction(IASTExpression functionNameExpression) {
return null;
}
@Override
protected Optional<Integer> evaluateDeferredFunction(final IASTFunctionCallExpression funcCall,
final IASTInitializerClause arg, int argPos, int indirection, IBinding defFunctionBinding) {
return Optional.empty();
}
}

View file

@ -15,8 +15,11 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
@ -25,6 +28,8 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
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.IPointerType;
import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType;
@ -36,6 +41,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeferredFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
@ -50,7 +57,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
private static CPPVariableReadWriteFlags INSTANCE = new CPPVariableReadWriteFlags();
public static int getReadWriteFlags(IASTName variable) {
public static Optional<Integer> getReadWriteFlags(IASTName variable) {
CPPSemantics.pushLookupPoint(variable);
try {
return INSTANCE.rwAnyNode(variable, 0);
@ -60,28 +67,29 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
}
@Override
protected int rwAnyNode(IASTNode node, int indirection) {
protected Optional<Integer> rwAnyNode(IASTNode node, int indirection) {
final IASTNode parent = node.getParent();
if (parent instanceof ICPPASTConstructorInitializer) {
return rwInCtorInitializer(node, indirection, (ICPPASTConstructorInitializer) parent);
}
if (parent instanceof ICPPASTFieldDesignator) {
return WRITE; // Field is initialized via a designated initializer.
return Optional.of(WRITE); // Field is initialized via a designated initializer.
}
return super.rwAnyNode(node, indirection);
}
@Override
protected int rwInDeclarator(IASTDeclarator parent, int indirection) {
protected Optional<Integer> rwInDeclarator(IASTDeclarator parent, int indirection) {
IType type = CPPVisitor.createType(parent);
if (type instanceof ICPPUnknownType || type instanceof ICPPClassType
&& !TypeTraits.hasTrivialDefaultConstructor((ICPPClassType) type, CPPSemantics.MAX_INHERITANCE_DEPTH)) {
return WRITE;
return Optional.of(WRITE);
}
return super.rwInDeclarator(parent, indirection);
}
private int rwInCtorInitializer(IASTNode node, int indirection, ICPPASTConstructorInitializer parent) {
private Optional<Integer> rwInCtorInitializer(IASTNode node, int indirection,
ICPPASTConstructorInitializer parent) {
IASTNode grand = parent.getParent();
if (grand instanceof IASTDeclarator || grand instanceof ICPPASTNewExpression) {
// Look for a constructor being called.
@ -112,33 +120,37 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
} else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
return Optional.empty(); // Fallback
}
@Override
protected int rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) {
protected Optional<Integer> rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) {
switch (expr.getOperator()) {
case ICPPASTUnaryExpression.op_typeid:
return 0;
return Optional.of(0);
}
return super.rwInUnaryExpression(node, expr, indirection);
}
@Override
protected int rwInFunctionName(IASTExpression node) {
protected Optional<Integer> rwInFunctionName(IASTExpression node) {
if (!(node instanceof IASTIdExpression)) {
IType type = node.getExpressionType();
if (type instanceof ICPPFunctionType && !((ICPPFunctionType) type).isConst())
return READ | WRITE;
return Optional.of(READ | WRITE);
}
return READ;
return Optional.of(READ);
}
@Override
protected int rwAssignmentToType(IType type, int indirection) {
protected Optional<Integer> rwAssignmentToType(IType type, int indirection) {
if (CPPTemplates.isDependentType(type)) {
return Optional.empty(); // Fallback
}
if (indirection == 0) {
if (!(type instanceof ICPPReferenceType) || ((ICPPReferenceType) type).isRValueReference()) {
return READ;
return Optional.of(READ);
}
type = ((ICPPReferenceType) type).getType();
}
@ -150,11 +162,59 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
}
if (indirection == 0) {
if (type instanceof IQualifierType) {
return ((IQualifierType) type).isConst() ? READ : READ | WRITE;
return ((IQualifierType) type).isConst() ? Optional.of(READ) : Optional.of(READ | WRITE);
} else if (type instanceof IPointerType) {
return ((IPointerType) type).isConst() ? READ : READ | WRITE;
return ((IPointerType) type).isConst() ? Optional.of(READ) : Optional.of(READ | WRITE);
}
}
return READ | WRITE; // fallback
return Optional.empty(); // Fallback
}
@Override
protected IBinding getDeferredFunction(IASTExpression functionNameExpression) {
if (functionNameExpression instanceof IASTIdExpression) {
IBinding b = ((IASTIdExpression) functionNameExpression).getName().resolveBinding();
if (b instanceof ICPPDeferredFunction) {
return b;
}
}
return null;
}
@Override
protected Optional<Integer> evaluateDeferredFunction(final IASTFunctionCallExpression funcCall,
final IASTInitializerClause arg, int argPos, int indirection, IBinding defFunctionBinding) {
ICPPDeferredFunction deferredFunc = (defFunctionBinding instanceof ICPPDeferredFunction)
? (ICPPDeferredFunction) defFunctionBinding
: null;
if (deferredFunc == null)
return Optional.empty();
ICPPFunction[] candidates = deferredFunc.getCandidates();
if (candidates != null) {
Optional<Integer> cumulative = Optional.empty();
for (ICPPFunction f : candidates) {
IType type = f.getType();
if (type instanceof IFunctionType) {
Optional<Integer> res = rwArgumentForFunctionCall((IFunctionType) type, argPos, arg, indirection);
cumulative = bitwiseOr(cumulative, res);
} 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) {
Optional<Integer> res = rwArgumentForFunctionCall(((IFunction) binding).getType(), argPos,
arg, indirection);
cumulative = bitwiseOr(cumulative, res);
}
}
}
}
return cumulative;
}
return Optional.empty(); // Fallback
}
}

View file

@ -56,6 +56,7 @@ public final class PDOMName implements IIndexFragmentName {
public static final int IS_FRIEND_SPEC = 0x08;
public static final int IS_INLINE_NAMESPACE = 0x0C;
public static final int COULD_BE_POLYMORPHIC_METHOD_CALL = 0x10;
//TODO We haven't got any flag for "unknown" access, we should add it to the index
public static final int READ_ACCESS = 0x20;
public static final int WRITE_ACCESS = 0x40;
// Whether this name is a potential match for its binding, rather than an exact match.

View file

@ -15,6 +15,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.c;
import java.util.Optional;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
@ -138,7 +140,11 @@ class PDOMCVariable extends PDOMBinding implements IVariable {
@Override
public int getAdditionalNameFlags(int standardFlags, IASTName name) {
if ((standardFlags & PDOMName.IS_REFERENCE) == PDOMName.IS_REFERENCE) {
return CVariableReadWriteFlags.getReadWriteFlags(name);
Optional<Integer> res = CVariableReadWriteFlags.getReadWriteFlags(name);
if (!res.isPresent()) {
return PDOMName.WRITE_ACCESS | PDOMName.READ_ACCESS;
}
return res.get();
}
return 0;
}

View file

@ -15,6 +15,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import java.util.Optional;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
@ -162,7 +164,11 @@ class PDOMCPPVariable extends PDOMCPPBinding implements ICPPVariable {
@Override
public int getAdditionalNameFlags(int standardFlags, IASTName name) {
if ((standardFlags & PDOMName.IS_REFERENCE) == PDOMName.IS_REFERENCE) {
return CPPVariableReadWriteFlags.getReadWriteFlags(name);
Optional<Integer> res = CPPVariableReadWriteFlags.getReadWriteFlags(name);
if (!res.isPresent()) {
return PDOMName.READ_ACCESS | PDOMName.WRITE_ACCESS;
}
return res.get();
}
return 0;
}

View file

@ -17,6 +17,7 @@ package org.eclipse.cdt.internal.corext.refactoring.code.flow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
@ -918,10 +919,10 @@ abstract class FlowAnalyzer extends ASTGenericVisitor {
if (!(variable instanceof IField)) {
int index = fFlowContext.getIndexFromLocal(variable);
if (index >= 0) {
int accessMode = CPPVariableReadWriteFlags.getReadWriteFlags(node);
if (accessMode != 0) {
Optional<Integer> accessMode = CPPVariableReadWriteFlags.getReadWriteFlags(node);
if (accessMode.isPresent() && accessMode.get() != 0) {
int flowInfoMode = FlowInfo.UNUSED;
switch (accessMode) {
switch (accessMode.get()) {
case PDOMName.READ_ACCESS:
flowInfoMode = FlowInfo.READ;
break;
@ -933,6 +934,8 @@ abstract class FlowAnalyzer extends ASTGenericVisitor {
break;
}
setFlowInfo(node, new LocalFlowInfo(variable, index, flowInfoMode, fFlowContext));
} else if (!accessMode.isPresent()) {
setFlowInfo(node, new LocalFlowInfo(variable, index, FlowInfo.UNKNOWN, fFlowContext));
}
}
}

View file

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
@ -43,7 +44,6 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVariableReadWriteFlags;
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowContext;
import org.eclipse.cdt.internal.corext.refactoring.code.flow.FlowInfo;
import org.eclipse.cdt.internal.corext.refactoring.code.flow.InputFlowAnalyzer;
@ -179,8 +179,8 @@ public class NodeContainer {
if (!hasReferenceOperator(declarator)) {
for (NameInformation n2 : names) {
if (n2.getDeclarationName() == declarationName) {
int flag = CPPVariableReadWriteFlags.getReadWriteFlags(n2.getName());
if ((flag & PDOMName.WRITE_ACCESS) != 0) {
Optional<Integer> flags = CPPVariableReadWriteFlags.getReadWriteFlags(n2.getName());
if (CPPVariableReadWriteFlags.mayBeWriteAccess(flags)) {
nameInfo.setWriteAccess(true);
break;
}

View file

@ -14,6 +14,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.ui.search;
import java.util.Optional;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
@ -62,9 +64,11 @@ public class CSearchUtil {
public static boolean isWriteOccurrence(IASTName node, IBinding binding) {
boolean isWrite;
if (binding instanceof ICPPVariable) {
isWrite = ((CPPVariableReadWriteFlags.getReadWriteFlags(node) & PDOMName.WRITE_ACCESS) != 0);
Optional<Integer> res = CPPVariableReadWriteFlags.getReadWriteFlags(node);
isWrite = !res.isPresent() || ((res.get() & PDOMName.WRITE_ACCESS) != 0);
} else {
isWrite = ((CVariableReadWriteFlags.getReadWriteFlags(node) & PDOMName.WRITE_ACCESS) != 0);
Optional<Integer> res = CVariableReadWriteFlags.getReadWriteFlags(node);
isWrite = !res.isPresent() || ((res.get() & PDOMName.WRITE_ACCESS) != 0);
}
return isWrite;
}