From 81c9f2d7555147406dc00e29e4641d409e89a0c9 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Tue, 4 Dec 2012 20:41:54 -0800 Subject: [PATCH] Bug 393068 - Constructor call is treated as write access for arguments --- .../ast2/VariableReadWriteFlagsTest.java | 37 +++++----- .../dom/parser/cpp/CPPASTNewExpression.java | 42 +++++++++--- .../parser/cpp/semantics/CPPSemantics.java | 67 +++++++++++++------ .../semantics/CPPVariableReadWriteFlags.java | 3 +- 4 files changed, 102 insertions(+), 47 deletions(-) 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 694a90a7186..494d56817d3 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 @@ -165,24 +165,31 @@ public class VariableReadWriteFlagsTest extends AST2BaseTest { // }; // // void test(int a, int b, int c) { - // A(&a, b); - // A x(&a, b); - // A(&a, b, c); - // A y(&a, b, c); + // A u = A(&a, b); + // A* v = new A(&a, b); + // A w(&a, b); + // A x = A(&a, b, c); + // A* y = new A(&a, b, c); + // A z(&a, b, c); // }; 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("x(&a, b)", "a", READ | WRITE); -// a.assertReadWriteFlags("x(&a, b)", "b", READ | WRITE); -// a.assertReadWriteFlags("x(&a, b)", "x", WRITE); - a.assertReadWriteFlags("A(&a, b, c)", "a", READ); - a.assertReadWriteFlags("A(&a, b, c)", "b", READ); - a.assertReadWriteFlags("A(&a, b, c)", "c", READ); - a.assertReadWriteFlags("y(&a, b, c)", "a", READ); - a.assertReadWriteFlags("y(&a, b, c)", "b", READ); - a.assertReadWriteFlags("y(&a, b, c)", "c", READ); + 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("w(&a, b)", "w", WRITE); + a.assertReadWriteFlags("= A(&a, b, c)", "a", READ); + a.assertReadWriteFlags("= A(&a, b, c)", "b", READ); + a.assertReadWriteFlags("= A(&a, b, c)", "c", READ); + a.assertReadWriteFlags("new A(&a, b, c)", "a", READ); + a.assertReadWriteFlags("new A(&a, b, c)", "b", READ); + a.assertReadWriteFlags("new A(&a, b, c)", "c", READ); + a.assertReadWriteFlags("z(&a, b, c)", "a", READ); + a.assertReadWriteFlags("z(&a, b, c)", "b", READ); + a.assertReadWriteFlags("z(&a, b, c)", "c", READ); } // struct A { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java index 5e91fcc7148..ac823d098d6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java @@ -1,14 +1,15 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2012 IBM Corporation 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * John Camelon (IBM) - Initial API and implementation - * Markus Schorn (Wind River Systems) - * Mike Kucera (IBM) + * John Camelon (IBM) - Initial API and implementation + * Markus Schorn (Wind River Systems) + * Mike Kucera (IBM) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -30,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; @@ -46,7 +48,7 @@ public class CPPASTNewExpression extends ASTNode implements ICPPASTNewExpression private IASTInitializerClause[] placement; private IASTTypeId typeId; private IASTInitializer initializer; - private IASTImplicitName[] implicitNames = null; + private IASTImplicitName[] implicitNames; private boolean isGlobal; private boolean isNewTypeId; @@ -163,15 +165,35 @@ public class CPPASTNewExpression extends ASTNode implements ICPPASTNewExpression @Override public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { + CPPASTImplicitName operatorName = null; ICPPFunction operatorFunction = CPPSemantics.findOverloadedOperator(this); - if (operatorFunction == null || operatorFunction instanceof CPPImplicitFunction) { - implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; - } else { - CPPASTImplicitName operatorName = new CPPASTImplicitName(operatorFunction.getNameCharArray(), this); + if (operatorFunction != null && !(operatorFunction instanceof CPPImplicitFunction)) { + operatorName = new CPPASTImplicitName(operatorFunction.getNameCharArray(), this); operatorName.setOperator(true); operatorName.setBinding(operatorFunction); operatorName.setOffsetAndLength(getOffset(), 3); - implicitNames = new IASTImplicitName[] { operatorName }; + } + + CPPASTImplicitName constructorName = null; + ICPPConstructor constructor = CPPSemantics.findImplicitlyCalledConstructor(this); + if (constructor != null) { + constructorName = new CPPASTImplicitName(constructor.getNameCharArray(), this); + constructorName.setBinding(constructor); + constructorName.setOffsetAndLength((ASTNode) getTypeId()); + } + + if (operatorName != null) { + if (constructorName != null) { + implicitNames = new IASTImplicitName[] { operatorName, constructorName }; + } else { + implicitNames = new IASTImplicitName[] { operatorName }; + } + } else { + if (constructorName != null) { + implicitNames = new IASTImplicitName[] { constructorName }; + } else { + implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; + } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 124537a41af..1f864db0ee6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -3097,9 +3097,10 @@ public class CPPSemantics { IBinding binding = name.resolveBinding(); if (!(binding instanceof ICPPVariable)) return null; - IType type; + + IType type = ((ICPPVariable) binding).getType(); try { - type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE); + type = SemanticUtil.getNestedType(type, TDEF | CVTYPE); if (!(type instanceof ICPPClassType)) return null; if (type instanceof ICPPClassTemplate || type instanceof ICPPUnknownType || type instanceof ISemanticProblem) @@ -3107,7 +3108,7 @@ public class CPPSemantics { final ICPPClassType classType = (ICPPClassType) type; if (initializer instanceof IASTEqualsInitializer) { - // Copy initialization + // Copy initialization. IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer; ICPPASTInitializerClause initClause = (ICPPASTInitializerClause) eqInit.getInitializerClause(); final ICPPEvaluation evaluation = initClause.getEvaluation(); @@ -3128,7 +3129,7 @@ public class CPPSemantics { } } } else if (initializer instanceof ICPPASTInitializerList) { - // List initialization + // List initialization. ICPPEvaluation eval= ((ICPPASTInitializerList) initializer).getEvaluation(); if (eval instanceof EvalInitList) { Cost c= Conversions.listInitializationSequence((EvalInitList) eval, type, UDCMode.ALLOWED, true, name); @@ -3139,24 +3140,11 @@ public class CPPSemantics { } } } else if (initializer instanceof ICPPASTConstructorInitializer) { - // Direct Initialization - final IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initializer).getArguments(); - CPPASTName astName = new CPPASTName(); - astName.setName(classType.getNameCharArray()); - astName.setOffsetAndLength((ASTNode) name); - CPPASTIdExpression idExp = new CPPASTIdExpression(astName); - idExp.setParent(name.getParent()); - idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); - - LookupData data = new LookupData(astName); - data.setFunctionArguments(false, arguments); - data.qualified = true; - data.foundItems = ClassTypeHelper.getConstructors(classType, name); - binding = resolveAmbiguities(data); - if (binding instanceof ICPPConstructor) - return (ICPPConstructor) binding; + // Direct initialization. + return findImplicitlyCalledConstructor(classType, + (ICPPASTConstructorInitializer) initializer, name); } else if (initializer == null) { - // Default initialization + // Default initialization. ICPPConstructor[] ctors = ClassTypeHelper.getConstructors(classType, name); for (ICPPConstructor ctor : ctors) { if (ctor.getRequiredArgumentCount() == 0) @@ -3169,6 +3157,43 @@ public class CPPSemantics { return null; } + public static ICPPConstructor findImplicitlyCalledConstructor(ICPPASTNewExpression expr) { + IType type = getNestedType(expr.getExpressionType(), TDEF | REF | CVTYPE); + if (!(type instanceof IPointerType)) + return null; + type = ((IPointerType) type).getType(); + IASTInitializer initializer = expr.getInitializer(); + if (type instanceof ICPPClassType && initializer instanceof ICPPASTConstructorInitializer) { + return findImplicitlyCalledConstructor((ICPPClassType) type, + (ICPPASTConstructorInitializer) initializer, expr.getTypeId()); + } + return null; + } + + private static ICPPConstructor findImplicitlyCalledConstructor(ICPPClassType classType, + ICPPASTConstructorInitializer initializer, IASTNode typeId) { + final IASTInitializerClause[] arguments = initializer.getArguments(); + CPPASTName astName = new CPPASTName(); + astName.setName(classType.getNameCharArray()); + astName.setOffsetAndLength((ASTNode) typeId); + CPPASTIdExpression idExp = new CPPASTIdExpression(astName); + idExp.setParent(typeId.getParent()); + idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); + + LookupData data = new LookupData(astName); + data.setFunctionArguments(false, arguments); + data.qualified = true; + data.foundItems = ClassTypeHelper.getConstructors(classType, typeId); + IBinding binding; + try { + binding = resolveAmbiguities(data); + if (binding instanceof ICPPConstructor) + return (ICPPConstructor) binding; + } catch (DOMException e) { + } + return null; + } + public static ICPPFunction findImplicitlyCalledDestructor(ICPPASTDeleteExpression expr) { IType t = getTypeOfPointer(expr.getOperand().getExpressionType()); if (!(t instanceof ICPPClassType)) 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 5a07c5e916f..0e43dbdec01 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 @@ -25,6 +25,7 @@ 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.ICPPASTNewExpression; 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; @@ -68,7 +69,7 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags { private int rwInCtorInitializer(IASTNode node, int indirection, ICPPASTConstructorInitializer parent) { IASTNode grand= parent.getParent(); - if (grand instanceof IASTDeclarator) { + if (grand instanceof IASTDeclarator || grand instanceof ICPPASTNewExpression) { // Look for a constructor being called. if (grand instanceof IASTImplicitNameOwner) { IASTImplicitName[] names = ((IASTImplicitNameOwner) grand).getImplicitNames();