1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Bug 370887 - CPPVariableReadWriteFlags.getReadWriteFlags returns

incorrect results.
This commit is contained in:
Sergey Prigogin 2012-02-08 17:30:00 -08:00
parent 69457e8aec
commit 61e9d699ba
7 changed files with 175 additions and 68 deletions

View file

@ -597,11 +597,27 @@ public class AST2BaseTest extends BaseTestCase {
public IASTName findName(String section, int len) {
final int offset = contents.indexOf(section);
assertTrue(offset >= 0);
assertTrue("Section \"" + section + "\" not found", offset >= 0);
IASTNodeSelector selector = tu.getNodeSelector(null);
return selector.findName(offset, len);
}
public IASTName findName(String context, String name) {
if (context == null) {
context = contents;
}
int offset = contents.indexOf(context);
assertTrue("Context \"" + context + "\" not found", offset >= 0);
int nameOffset = context.indexOf(name);
assertTrue("Name \"" + name + "\" not found", nameOffset >= 0);
IASTNodeSelector selector = tu.getNodeSelector(null);
return selector.findName(offset + nameOffset, name.length());
}
public IASTName findName(String name) {
return findName(contents, name);
}
public IASTName findImplicitName(String section, int len) {
final int offset = contents.indexOf(section);
assertTrue(offset >= 0);

View file

@ -32,21 +32,16 @@ public class VariableReadWriteFlagsTest extends AST2BaseTest {
super(contents, isCPP);
}
void assertReadWriteFlags(String section, int expectedFlags) throws Exception {
int len;
for (len = 0; len < section.length(); len++) {
if (!Character.isJavaIdentifierPart(section.charAt(len)))
break;
}
assertReadWriteFlags(section, len, expectedFlags);
}
void assertReadWriteFlags(String section, int len, int expectedFlags) throws Exception {
IASTName variable = findName(section, len);
void assertReadWriteFlags(String context, String name, int 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);
}
int getReadWriteFlags(IASTName variable) {
return isCPP ?
CPPVariableReadWriteFlags.getReadWriteFlags(variable) :
@ -90,71 +85,101 @@ public class VariableReadWriteFlagsTest extends AST2BaseTest {
return new AssertionHelper(code, true);
}
// int test() {
// int a;
// int test(int a) {
// a = 2;
// a *= 3;
// return a + 1;
// }
public void testSimpleAccess() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a = 2", WRITE);
a.assertReadWriteFlags("a +", READ);
a.assertReadWriteFlags("a = 2", "a", WRITE);
a.assertReadWriteFlags("a *= 3", "a", READ | WRITE);
a.assertReadWriteFlags("a + 1", "a", READ);
}
// int a = 1;
public void _testEqualsInitializer() throws Exception {
// class C {
// public:
// C(int);
// };
//
// class D {
// public:
// D();
// };
//
// int a;
// int b = 1;
// C c;
// D d;
// C e(1);
// template<typename T> void foo(T p) {
// T f;
// }
public void testVariableDeclaration() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a", WRITE);
a.assertReadWriteFlags("int a", "a", 0);
a.assertReadWriteFlags("int b = 1", "b", WRITE);
a.assertReadWriteFlags("C c", "c", 0);
a.assertReadWriteFlags("D d", "d", WRITE);
a.assertReadWriteFlags("C e(1)", "e", WRITE);
a.assertReadWriteFlags("T f", "f", WRITE);
}
// struct A { int x; };
//
// void test() {
// A a;
// void test(A a, A* ap) {
// a.x = 1;
// (&a)->x = 1;
// ap->x = 1;
// };
public void testFieldAccess() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a.", WRITE);
a.assertReadWriteFlags("a.x", "a", WRITE);
a.assertReadWriteFlags("a.x", "x", WRITE);
a.assertReadWriteFlags("(&a)->x", "a", WRITE);
a.assertReadWriteFlags("(&a)->x", "x", WRITE);
a.assertReadWriteFlags("ap->x", "ap", READ);
a.assertReadWriteFlags("ap->x", "x", WRITE);
}
// struct A { int x; };
// void f(int* x, int& y);
// void g(const int* x, const int& y, int z);
//
// void test(A* a) {
// a->x = 1;
// void test(int a, int b, int c) {
// f(&a, b);
// g(&a, b, c);
// };
public void testFieldAccessWithDereference() throws Exception {
public void testFunctionCall() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a->", READ);
}
// void f(int* x);
// void g(const int* x);
//
// void test() {
// int a, b;
// f(&a);
// g(&b);
// };
public void testExplicitArgument() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a)", READ | WRITE);
a.assertReadWriteFlags("b)", READ);
a.assertReadWriteFlags("f(&a, b)", "a", READ | WRITE);
a.assertReadWriteFlags("f(&a, b)", "b", READ | WRITE);
a.assertReadWriteFlags("f(&a, b)", "f", READ);
a.assertReadWriteFlags("g(&a, b, c)", "a", READ);
a.assertReadWriteFlags("g(&a, b, c)", "b", READ);
a.assertReadWriteFlags("g(&a, b, c)", "c", READ);
}
// struct A {
// void m1();
// void m2() const;
// void m();
// void mc() const;
// };
//
// void test() {
// A a;
// a.m1();
// a.m2();
// void test(A a, A* ap) {
// a.m();
// a.mc();
// (&a)->m();
// (&a)->mc();
// ap->m();
// (*ap).m();
// };
public void testImplicitArgument() throws Exception {
public void testMethodCall() throws Exception {
AssertionHelper a = getCPPAssertionHelper();
a.assertReadWriteFlags("a.m1", READ | WRITE);
a.assertReadWriteFlags("a.m2", READ);
a.assertReadWriteFlags("a.m()", "a", READ | WRITE);
a.assertReadWriteFlags("a.m()", "m", READ);
a.assertReadWriteFlags("a.mc()", "a", READ);
a.assertReadWriteFlags("(&a)->m()", "a", READ | WRITE);
a.assertReadWriteFlags("(&a)->m()", "m", READ);
a.assertReadWriteFlags("ap->m()", "ap", READ);
a.assertReadWriteFlags("(*ap).m()", "ap", READ);
}
}

View file

@ -57,15 +57,14 @@ public abstract class VariableReadWriteFlags {
protected static final int READ = PDOMName.READ_ACCESS;
protected static final int WRITE = PDOMName.WRITE_ACCESS;
protected VariableReadWriteFlags() {
}
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) {
@ -76,6 +75,12 @@ public abstract class VariableReadWriteFlags {
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) {
@ -112,11 +117,7 @@ public abstract class VariableReadWriteFlags {
return rwInBinaryExpression(node, (IASTBinaryExpression) expr, indirection);
}
if (expr instanceof IASTFieldReference) {
if (node.getPropertyInParent() != IASTFieldReference.FIELD_OWNER ||
!((IASTFieldReference) expr).isPointerDereference()) {
return rwAnyNode(expr, indirection);
}
return READ;
return rwInFieldReference(node, (IASTFieldReference) expr, indirection);
}
if (expr instanceof IASTCastExpression) { // must be ahead of unary
return rwAnyNode(expr, indirection);
@ -126,7 +127,7 @@ public abstract class VariableReadWriteFlags {
}
if (expr instanceof IASTArraySubscriptExpression) {
if (indirection > 0 && node.getPropertyInParent() == IASTArraySubscriptExpression.ARRAY) {
return rwAnyNode(expr, indirection-1);
return rwAnyNode(expr, indirection - 1);
}
return READ;
}
@ -146,7 +147,7 @@ public abstract class VariableReadWriteFlags {
}
if (expr instanceof IASTFunctionCallExpression) {
if (node.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
return rwFunctionName((IASTExpression) node);
return rwInFunctionName((IASTExpression) node);
}
return rwArgumentForFunctionCall((IASTFunctionCallExpression) expr, node, indirection);
}
@ -160,7 +161,20 @@ public abstract class VariableReadWriteFlags {
return READ | WRITE; // fall back
}
protected int rwFunctionName(IASTExpression node) {
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;
}
@ -206,7 +220,7 @@ public abstract class VariableReadWriteFlags {
while (parent instanceof IASTCompoundStatement) {
IASTCompoundStatement compound= (IASTCompoundStatement) parent;
IASTStatement[] statements= compound.getStatements();
if (statements[statements.length-1] != stmt) {
if (statements[statements.length - 1] != stmt) {
return 0;
}
stmt= compound;

View file

@ -870,6 +870,42 @@ public class ClassTypeHelper {
return null;
}
/**
* Returns <code>true</code> if and only if the given class has a trivial default constructor.
* A default constructor is trivial if:
* <ul>
* <li>it is implicitly defined by the compiler, and</li>
* <li>every direct base class has trivial default constructor, and</li>
* <li>for every nonstatic data member that has class type or array of class type, that type
* has trivial default constructor.</li>
* </ul>
* Similar to <code>std::tr1::has_trivial_default_constructor</code>.
*
* @param classTarget the class to check
* @return <code>true</code> if the class has a trivial default constructor
*/
public static boolean hasTrivialDefaultConstructor(ICPPClassType classTarget) {
for (ICPPConstructor ctor : classTarget.getConstructors()) {
if (!ctor.isImplicit() && ctor.getParameters().length == 0)
return false;
}
for (ICPPClassType baseClass : getAllBases(classTarget)) {
if (!classTarget.isSameType(baseClass) && !hasTrivialDefaultConstructor(baseClass))
return false;
}
for (ICPPField field : classTarget.getDeclaredFields()) {
if (!field.isStatic()) {
IType type = field.getType();
type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY);
if (type instanceof ICPPClassType && !classTarget.isSameType(type) &&
!hasTrivialDefaultConstructor((ICPPClassType) type)) {
return false;
}
}
}
return true;
}
/**
* Returns <code>true</code> if and only if the given class has a trivial destructor.
* A destructor is trivial if:

View file

@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTName;
@ -25,11 +26,14 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
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.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.VariableReadWriteFlags;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
/**
* Helper class to determine whether a variable is accessed for reading and/or writing.
@ -52,6 +56,17 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
return super.rwAnyNode(node, indirection);
}
@Override
protected int rwInDeclarator(IASTDeclarator parent, int indirection) {
IType type = CPPVisitor.createType(parent);
if (type instanceof ICPPUnknownType ||
type instanceof ICPPClassType &&
!ClassTypeHelper.hasTrivialDefaultConstructor((ICPPClassType) type)) {
return WRITE;
}
return super.rwInDeclarator(parent, indirection);
}
private int rwInCtorInitializer(IASTNode node, int indirection, ICPPASTConstructorInitializer parent) {
IASTNode grand= parent.getParent();
if (grand instanceof IASTDeclarator) {
@ -94,10 +109,12 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
}
@Override
protected int rwFunctionName(IASTExpression node) {
IType type= node.getExpressionType();
if (type instanceof ICPPFunctionType && !((ICPPFunctionType) type).isConst())
return READ | WRITE;
protected int rwInFunctionName(IASTExpression node) {
if (!(node instanceof IASTIdExpression)) {
IType type= node.getExpressionType();
if (type instanceof ICPPFunctionType && !((ICPPFunctionType) type).isConst())
return READ | WRITE;
}
return READ;
}

View file

@ -881,7 +881,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// return extracted(b, &a) + a.const_method();
//}
public void _testOutputParameterWithMethodCall() throws Exception {
// Currently fails due to http://bugs.eclipse.org/bugs/show_bug.cgi?id=370887
getPreferenceStore().setValue(PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER, true);
assertRefactoringSuccess();
}

View file

@ -357,7 +357,7 @@ public class MarkOccurrenceTest extends BaseUITestCase {
fEditor.selectAndReveal(fMatch.getOffset(), fMatch.getLength());
assertOccurrences(2, 1);
assertOccurrences(2, 0);
assertOccurrencesInWidget();
}