From 4933b90d3e17417b6ad5f2e1fca14050dd4b902d Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Fri, 1 Jul 2011 10:42:46 +0200 Subject: [PATCH] Bug 328528: Read/write flags in initializers. --- .../internal/index/tests/IndexNamesTests.java | 146 ++++++++++++------ .../dom/parser/VariableReadWriteFlags.java | 108 +++++++------ .../dom/parser/c/CVariableReadWriteFlags.java | 22 +-- .../semantics/CPPVariableReadWriteFlags.java | 51 +++++- 4 files changed, 215 insertions(+), 112 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java index f63a74baa1c..2b220298a8d 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java @@ -67,9 +67,9 @@ public class IndexNamesTests extends BaseTestCase { return fCProject.getProject(); } - protected StringBuffer[] getContentsForTest(int blocks) throws IOException { + public String getComment() throws IOException { return TestSourceReader.getContentsForTest( - CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), blocks); + CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), 1)[0].toString(); } protected IFile createFile(IContainer container, String fileName, String contents) throws Exception { @@ -102,7 +102,7 @@ public class IndexNamesTests extends BaseTestCase { // }; public void testNestingWithFunction() throws Exception { waitForIndexer(); - String content= getContentsForTest(1)[0].toString(); + String content= getComment(); IFile file= createFile(getProject().getProject(), "test.cpp", content); waitUntilFileIsIndexed(file, 4000); @@ -161,7 +161,7 @@ public class IndexNamesTests extends BaseTestCase { // }; public void testNestingWithMethod() throws Exception { waitForIndexer(); - String content= getContentsForTest(1)[0].toString(); + String content= getComment(); IFile file= createFile(getProject().getProject(), "test.cpp", content); waitUntilFileIsIndexed(file, 4000); @@ -257,7 +257,7 @@ public class IndexNamesTests extends BaseTestCase { // } public void testCouldBePolymorphicMethodCall_Bug156691() throws Exception { waitForIndexer(); - String content= getContentsForTest(1)[0].toString(); + String content= getComment(); IFile file= createFile(getProject().getProject(), "test.cpp", content); waitUntilFileIsIndexed(file, 4000); @@ -315,7 +315,7 @@ public class IndexNamesTests extends BaseTestCase { // } public void testReadWriteFlagsC() throws Exception { waitForIndexer(); - String content= getContentsForTest(1)[0].toString(); + String content= getComment(); IFile file= createFile(getProject().getProject(), "test.c", content); waitUntilFileIsIndexed(file, 4000); @@ -329,16 +329,15 @@ public class IndexNamesTests extends BaseTestCase { IIndexFile ifile= fIndex.getFile(linkageID, IndexLocationFactory.getWorkspaceIFL(file)); IIndexName[] names= ifile.findNames(0, Integer.MAX_VALUE); int j= 0; - for (int i = 0; i < names.length; i++) { - IIndexName indexName = names[i]; + for (IIndexName indexName : names) { final String name = indexName.toString(); final char c0= name.length() > 0 ? name.charAt(0) : 0; if ((c0 == '_' || c0 == 'r' || c0 == 'w') && indexName.isReference()) { - boolean isRead= name.charAt(0) == 'r' || name.charAt(0) == 'u'; - boolean isWrite= name.charAt(isRead ? 1 : 0) == 'w' || name.charAt(0) == 'u'; - String msg= "i=" + i + ", " + name + ":"; - assertEquals(msg, isRead, indexName.isReadAccess()); - assertEquals(msg, isWrite, indexName.isWriteAccess()); + boolean isRead= name.charAt(0) == 'r'; + boolean isWrite= c0 == 'w' || (isRead && name.length() > 1 && name.charAt(1) == 'w'); + String msg= name + "(j=" + j + "):"; + assertEquals("Read access for " + msg, isRead, indexName.isReadAccess()); + assertEquals("Write access for " + msg, isWrite, indexName.isWriteAccess()); j++; } else { @@ -352,50 +351,99 @@ public class IndexNamesTests extends BaseTestCase { } } - // int _i, ri, wi, rwi, rfind, ui; - // int* rp; int* wp; int* rwp; int* up; - // int* const rpc= 0; - // const int * const rcpc= 0; - // const int* cip= &ri; - // int* bla= &rwi; - // void fi(int); - // void fp(int*); - // void fr(int&); - // void fcp(const int*); - // void fcr(const int&); - // void fpp(int**); - // void fpr(int*&); - // void fcpp(int const**); - // void fcpr(int const*&); - // void fpcp(int *const*); - // void fpcr(int *const&); - // void fcpcp(int const *const*); - // void fcpcr(int const *const&); - // + // int _i, ri, wi, rwi; + // int* rp; int* wp; int* rwp; + // int* const rpc= 0; + // const int * const rcpc= 0; + // const int* rwcp= &ri; + // void fi(int); + // void fp(int*); + // void fr(int&); + // void fcp(const int*); + // void fcr(const int&); + // void fpp(int**); + // void fpr(int*&); + // void fcpp(int const**); + // void fcpr(int const*&); + // void fpcp(int *const*); + // void fpcr(int *const&); + // void fcpcp(int const *const*); + // void fcpcr(int const *const&); // int test() { - // _i; + // _i; // wi= ri, _i, _i; // expr-list - // rwi %= ri; // assignment - // ri ? _i : _i; // conditional - // (ri ? wi : wi)= ri; // conditional - // if (ri) _i; - // for(wi=1; ri>ri; rwi++) _i; + // rwi %= ri; // assignment + // ri ? _i : _i; // conditional + // (ri ? wi : wi)= ri; // conditional + // if (ri) _i; + // for(wi=1; ri>ri; rwi++) _i; // do {_i;} while (ri); - // while(ri) {_i;}; - // switch(ri) {case ri: _i;}; - // fi(ri); fp(&rwi); fcp(&ri); - // fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&up); fpcp(&rpc); fcpcp(&rcpc); - // fr(rwi); fcr(ri); fpr(&ui); - // fcpr(&ui); fpcr(&rwi); fcpcr(&ri); - // fpr(rwp); fcpr(up); fpcr(rp); fcpcr(rp); - // return ri; + // while(ri) {_i;}; + // switch(ri) {case ri: _i;}; + // fi(ri); fp(&rwi); fcp(&ri); + // fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&rwcp); fpcp(&rpc); fcpcp(&rcpc); + // fr(rwi); fcr(ri); + // fpcr(&rwi); fcpcr(&ri); + // fpr(rwp); fcpr(rwcp); fpcr(rp); fcpcr(rp); + // return ri; // } public void testReadWriteFlagsCpp() throws Exception { waitForIndexer(); - String content= getContentsForTest(1)[0].toString(); + String content= getComment(); IFile file= createFile(getProject().getProject(), "test.cpp", content); waitUntilFileIsIndexed(file, 4000); - checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 47); + checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 48); + } + + + // int _i, ri, wi, rwi; + // void f(int&, int); + // void g(int, int&); + // void test() { + // f(rwi, ri); + // g(ri, rwi); + // } + public void testRWInSecondArg() throws Exception { + waitForIndexer(); + String content= getComment(); + IFile file= createFile(getProject().getProject(), "testRWInSecondArg.cpp", content); + waitUntilFileIsIndexed(file, 4000); + + checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 4); + } + + // struct A { + // A(int p) {} + // }; + // int r; + // A a(r); // Should be read-access + // void test() { + // A b(r); // Should be read-access + // } + public void testRWInConstructorCall_328528() throws Exception { + waitForIndexer(); + String content= getComment(); + IFile file= createFile(getProject().getProject(), "testRWInConstructorCall.cpp", content); + waitUntilFileIsIndexed(file, 4000); + + checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 2); + } + + // struct A { + // A(int p) {} + // }; + // int r; + // int a[2] = {0, r}; // Should be read-access + // void test() { + // int b[2] = {0, r}; // Should be read-access + // } + public void testRWInArrayInitializer_328528() throws Exception { + waitForIndexer(); + String content= getComment(); + IFile file= createFile(getProject().getProject(), "testRWInArrayInitializer.cpp", content); + waitUntilFileIsIndexed(file, 4000); + + checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 2); } } 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 42c8432cb0a..e968dfe3643 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -28,6 +28,8 @@ import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IASTInitializerList; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTProblemExpression; import org.eclipse.cdt.core.dom.ast.IASTProblemStatement; @@ -37,6 +39,7 @@ import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; +import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IType; @@ -58,23 +61,22 @@ public abstract class VariableReadWriteFlags { } protected int rwAnyNode(IASTNode node, int indirection) { - final IASTNode parent= node.getParent(); + final IASTNode parent = node.getParent(); if (parent instanceof IASTExpression) { - return rwInExpression(node, (IASTExpression) parent, indirection); + return rwInExpression((IASTExpression) parent, node, indirection); + } else if (parent instanceof IASTStatement) { + return rwInStatement((IASTStatement) parent, node, indirection); + } else if (parent instanceof IASTEqualsInitializer) { + return rwInEqualsInitializer((IASTEqualsInitializer) parent, indirection); + } else if (parent instanceof IASTArrayModifier) { + return READ; // dimension + } else if (parent instanceof IASTInitializerList) { + return rwInInitializerList((IASTInitializerList) parent, indirection); } - else if (parent instanceof IASTStatement) { - return rwInStatement(node, (IASTStatement) parent, indirection); - } - else if (parent instanceof IASTEqualsInitializer) { - return rwInInitializerExpression(indirection, parent); - } - else if (parent instanceof IASTArrayModifier) { - return READ; // dimension - } - return READ | WRITE; // fallback + return READ | WRITE; // fallback } - protected int rwInInitializerExpression(int indirection, IASTNode parent) { + protected int rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) { IASTNode grand= parent.getParent(); if (grand instanceof IASTDeclarator) { IBinding binding= ((IASTDeclarator) grand).getName().getBinding(); @@ -85,7 +87,24 @@ public abstract class VariableReadWriteFlags { return READ | WRITE; // fallback } - protected int rwInExpression(IASTNode node, IASTExpression expr, int indirection) { + protected int rwInInitializerList(IASTInitializerList parent, int indirection) { + IASTNode grand= parent.getParent(); + if (grand instanceof IASTEqualsInitializer) { + IASTNode grandGrand= grand.getParent(); + if (grandGrand instanceof IASTDeclarator) { + IBinding binding= ((IASTDeclarator) grandGrand).getName().resolveBinding(); + if (binding instanceof IVariable) { + IType type= ((IVariable) binding).getType(); + if (type instanceof IArrayType) { + return rwAssignmentToType(type, indirection); + } + } + } + } + return READ | WRITE; // fallback + } + + protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) { if (expr instanceof IASTBinaryExpression) { return rwInBinaryExpression(node, (IASTBinaryExpression) expr, indirection); } @@ -108,14 +127,8 @@ public abstract class VariableReadWriteFlags { return rwAnyNode(expr, indirection); } if (expr instanceof IASTExpressionList) { - final IASTExpressionList exprList = (IASTExpressionList)expr; - final IASTNode grand= expr.getParent(); - if (grand instanceof IASTFunctionCallExpression && expr.getPropertyInParent() == IASTFunctionCallExpression.ARGUMENT) { - final IASTFunctionCallExpression funcCall = (IASTFunctionCallExpression) grand; - return rwArgumentForFunctionCall(node, exprList, funcCall, indirection); - } - // only the first expression is passed on. - final IASTExpression[] expressions = exprList.getExpressions(); + // Only the first expression is passed on. + final IASTExpression[] expressions = ((IASTExpressionList) expr).getExpressions(); if (expressions.length > 0 && expressions[0] == node) { return rwAnyNode(expr, indirection); } @@ -131,7 +144,7 @@ public abstract class VariableReadWriteFlags { if (node.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) { return READ; } - return rwArgumentForFunctionCall((IASTFunctionCallExpression) expr, 0, indirection); + return rwArgumentForFunctionCall((IASTFunctionCallExpression) expr, node, indirection); } if (expr instanceof IASTIdExpression) { return rwAnyNode(expr, indirection); @@ -143,37 +156,38 @@ public abstract class VariableReadWriteFlags { return 0; } - return READ | WRITE; // fall back + return READ | WRITE; // fall back } - protected int rwArgumentForFunctionCall(IASTNode node, final IASTExpressionList exprList, - final IASTFunctionCallExpression funcCall, int indirection) { - final IASTExpression[] expressions = exprList.getExpressions(); - for (int i = 0; i < expressions.length; i++) { - if (expressions[i] == node) { - return rwArgumentForFunctionCall(funcCall, i, indirection); - } - } - return READ | WRITE;// fallback - } - - protected int rwArgumentForFunctionCall(final IASTFunctionCallExpression func, int parameterIdx, int indirection) { - final IASTExpression functionNameExpression = func.getFunctionNameExpression(); - if (functionNameExpression != null) { - final IType type= functionNameExpression.getExpressionType(); - if (type instanceof IFunctionType) { - IType[] ptypes= ((IFunctionType) type).getParameterTypes(); - if (ptypes != null && ptypes.length > parameterIdx) { - return rwAssignmentToType(ptypes[parameterIdx], indirection); + protected int rwArgumentForFunctionCall(final IASTFunctionCallExpression funcCall, IASTNode argument, int indirection) { + final IASTInitializerClause[] args = funcCall.getArguments(); + for (int i = 0; i < args.length; i++) { + if (args[i] == argument) { + final IASTExpression functionNameExpression = funcCall.getFunctionNameExpression(); + if (functionNameExpression != null) { + final IType type= functionNameExpression.getExpressionType(); + if (type instanceof IFunctionType) { + return rwArgumentForFunctionCall((IFunctionType) type, i, indirection); + } } + break; } } - return READ | WRITE; // fallback + return READ | WRITE; // fallback + } + + + protected int rwArgumentForFunctionCall(IFunctionType type, int parameterIdx, int indirection) { + IType[] ptypes= type.getParameterTypes(); + if (ptypes != null && ptypes.length > parameterIdx) { + return rwAssignmentToType(ptypes[parameterIdx], indirection); + } + return READ | WRITE; // Fallback } protected abstract int rwAssignmentToType(IType type, int indirection); - protected int rwInStatement(IASTNode node, IASTStatement stmt, int indirection) { + protected int rwInStatement(IASTStatement stmt, IASTNode node, int indirection) { if (stmt instanceof IASTCaseStatement) { if (node.getPropertyInParent() == IASTCaseStatement.EXPRESSION) { return READ; @@ -314,6 +328,6 @@ public abstract class VariableReadWriteFlags { } return READ; } - return READ; // fallback + return 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 b32c6c3a869..67704164d75 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 @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; +import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTExpressionList; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; @@ -45,35 +45,27 @@ public final class CVariableReadWriteFlags extends VariableReadWriteFlags { } @Override - protected int rwInExpression(IASTNode node, IASTExpression expr, int indirection) { + protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) { if (expr instanceof ICASTTypeIdInitializerExpression) { return 0; } - return super.rwInExpression(node, expr, indirection); + return super.rwInExpression(expr, node, indirection); } @Override - protected int rwInInitializerExpression(int indirection, IASTNode parent) { + protected int rwInEqualsInitializer(IASTEqualsInitializer parent, int indirection) { if (indirection == 0) { return READ; } - return super.rwInInitializerExpression(indirection, parent); + return super.rwInEqualsInitializer(parent, indirection); } @Override - protected int rwArgumentForFunctionCall(IASTFunctionCallExpression func, int parameterIdx,int indirection) { + protected int rwArgumentForFunctionCall(IASTFunctionCallExpression funcCall, IASTNode argument, int indirection) { if (indirection == 0) { return READ; } - return super.rwArgumentForFunctionCall(func, parameterIdx, indirection); - } - - @Override - protected int rwArgumentForFunctionCall(IASTNode node, IASTExpressionList exprList, IASTFunctionCallExpression funcCall, int indirection) { - if (indirection == 0) { - return READ; - } - return super.rwArgumentForFunctionCall(node, exprList, funcCall, indirection); + return super.rwArgumentForFunctionCall(funcCall, argument, indirection); } @Override 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 d5425756a40..89862e99f52 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,16 +7,24 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Patrick Hofer - [Bug 328528] *******************************************************************************/ 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.IASTImplicitName; +import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; 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.IPointerType; import org.eclipse.cdt.core.dom.ast.IQualifierType; 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.ICPPConstructor; 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; @@ -34,6 +42,47 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags { return INSTANCE.rwAnyNode(variable, 0); } + @Override + protected int rwAnyNode(IASTNode node, int indirection) { + final IASTNode parent = node.getParent(); + if (parent instanceof ICPPASTConstructorInitializer) { + return rwInCtorInitializer(node, indirection, (ICPPASTConstructorInitializer) parent); + } + return super.rwAnyNode(node, indirection); + } + + private int rwInCtorInitializer(IASTNode node, int indirection, ICPPASTConstructorInitializer parent) { + IASTNode grand= parent.getParent(); + if (grand instanceof IASTDeclarator) { + // Look for a constructor being called. + if (grand instanceof IASTImplicitNameOwner) { + IASTImplicitName[] names = ((IASTImplicitNameOwner) grand).getImplicitNames(); + for (IASTImplicitName in : names) { + IBinding b= in.resolveBinding(); + if (b instanceof ICPPConstructor) { + final ICPPConstructor ctor = (ICPPConstructor) b; + int idx= 0; + for (IASTNode child : parent.getArguments()) { + if (child == node) { + return rwArgumentForFunctionCall(ctor.getType(), idx, indirection); + } + idx++; + } + } + } + } + // Allow for initialization of primitive types. + if (parent.getArguments().length == 1) { + IBinding binding= ((IASTDeclarator) grand).getName().getBinding(); + if (binding instanceof IVariable) { + IType type= ((IVariable) binding).getType(); + return rwAssignmentToType(type, indirection); + } + } + } + return READ | WRITE; // fallback + } + @Override protected int rwInUnaryExpression(IASTNode node, IASTUnaryExpression expr, int indirection) { switch (expr.getOperator()) {