From 7a833fbb50c34f1307c0771d7e9a238b38c3da59 Mon Sep 17 00:00:00 2001 From: Marco Stornelli Date: Fri, 13 Mar 2020 09:04:11 +0100 Subject: [PATCH] Bug 561088 - Fix read/write flags in case of dependent types Change-Id: I072bb53a95d17137eb614bff34de6bd57a371d33 --- .../ClassMembersInitializationChecker.java | 5 +- .../ast2/VariableReadWriteFlagsTest.java | 56 ++++-- .../dom/parser/VariableReadWriteFlags.java | 180 ++++++++++++------ .../dom/parser/c/CVariableReadWriteFlags.java | 44 +++-- .../semantics/CPPVariableReadWriteFlags.java | 94 +++++++-- .../cdt/internal/core/pdom/dom/PDOMName.java | 1 + .../core/pdom/dom/c/PDOMCVariable.java | 8 +- .../core/pdom/dom/cpp/PDOMCPPVariable.java | 8 +- .../refactoring/code/flow/FlowAnalyzer.java | 9 +- .../ui/refactoring/NodeContainer.java | 6 +- .../cdt/internal/ui/search/CSearchUtil.java | 8 +- 11 files changed, 301 insertions(+), 118 deletions(-) diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java index f0ffaa5f35a..1821d129cbd 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ClassMembersInitializationChecker.java @@ -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 res = CPPVariableReadWriteFlags.getReadWriteFlags(name); + if (CPPVariableReadWriteFlags.mayBeWriteAccess(res)) { actualConstructorFields.remove(equivalentFieldBinding); } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/VariableReadWriteFlagsTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/VariableReadWriteFlagsTest.java index a0111a56922..a39ecccaded 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/VariableReadWriteFlagsTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/VariableReadWriteFlagsTest.java @@ -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 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 getReadWriteFlags(IASTName variable) { return isCPP ? CPPVariableReadWriteFlags.getReadWriteFlags(variable) : CVariableReadWriteFlags.getReadWriteFlags(variable); } - private String flagsToString(int flags) { + private String flagsToString(Optional 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 + //void g(S, T); + // + //struct A { + // int field; + // + // template + // void method3(S s) const { + // g(s, field); + // } + //}; + public void testDependentType() throws Exception { + AssertionHelper a = getCPPAssertionHelper(); + a.assertReadWriteFlags("g(s, field);", "field"); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java index 1d58c90b89a..173d60b63c5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java @@ -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 flags) { + if (!flags.isPresent() || (flags.get() & WRITE) != 0) + return true; + return false; + } + + protected Optional 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 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 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 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 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 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 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 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 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 bitwiseOr(Optional a, Optional b) { + Optional 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 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 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 rwAssignmentToType(IType type, int indirection); - protected int rwInStatement(IASTStatement stmt, IASTNode node, int indirection) { + protected Optional 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 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 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 } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVariableReadWriteFlags.java index 62f8baa7a67..100d2d4afe1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVariableReadWriteFlags.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVariableReadWriteFlags.java @@ -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 getReadWriteFlags(IASTName variable) { return INSTANCE.rwAnyNode(variable, 0); } @Override - protected int rwAnyNode(IASTNode node, int indirection) { + protected Optional 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 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 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 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 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 evaluateDeferredFunction(final IASTFunctionCallExpression funcCall, + final IASTInitializerClause arg, int argPos, int indirection, IBinding defFunctionBinding) { + return Optional.empty(); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java index e5ee18de9fa..0b4e321c0f2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java @@ -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 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 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 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 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 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 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 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 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 cumulative = Optional.empty(); + for (ICPPFunction f : candidates) { + IType type = f.getType(); + if (type instanceof IFunctionType) { + Optional 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 res = rwArgumentForFunctionCall(((IFunction) binding).getType(), argPos, + arg, indirection); + cumulative = bitwiseOr(cumulative, res); + } + } + } + } + return cumulative; + } + return Optional.empty(); // Fallback } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java index 9f73005f040..f8ac35b883f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java @@ -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. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCVariable.java index bfe51cec7a5..26cdd781a7a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCVariable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCVariable.java @@ -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 res = CVariableReadWriteFlags.getReadWriteFlags(name); + if (!res.isPresent()) { + return PDOMName.WRITE_ACCESS | PDOMName.READ_ACCESS; + } + return res.get(); } return 0; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPVariable.java index 6f02c5b78ee..af083b4f944 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPVariable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPVariable.java @@ -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 res = CPPVariableReadWriteFlags.getReadWriteFlags(name); + if (!res.isPresent()) { + return PDOMName.READ_ACCESS | PDOMName.WRITE_ACCESS; + } + return res.get(); } return 0; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java index ec01bb42528..d7915b35b77 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/refactoring/code/flow/FlowAnalyzer.java @@ -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 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)); } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java index ee93fc0ce12..277bacad3fa 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/NodeContainer.java @@ -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 flags = CPPVariableReadWriteFlags.getReadWriteFlags(n2.getName()); + if (CPPVariableReadWriteFlags.mayBeWriteAccess(flags)) { nameInfo.setWriteAccess(true); break; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/CSearchUtil.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/CSearchUtil.java index 959ccd3ba96..dfca53da4fc 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/CSearchUtil.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/CSearchUtil.java @@ -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 res = CPPVariableReadWriteFlags.getReadWriteFlags(node); + isWrite = !res.isPresent() || ((res.get() & PDOMName.WRITE_ACCESS) != 0); } else { - isWrite = ((CVariableReadWriteFlags.getReadWriteFlags(node) & PDOMName.WRITE_ACCESS) != 0); + Optional res = CVariableReadWriteFlags.getReadWriteFlags(node); + isWrite = !res.isPresent() || ((res.get() & PDOMName.WRITE_ACCESS) != 0); } return isWrite; }