mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-09 02:36:01 +02:00
Bug 156668: Implicit ctors for automatic variables.
This commit is contained in:
parent
ca68f6bb04
commit
200c531f33
7 changed files with 146 additions and 57 deletions
|
@ -9118,4 +9118,40 @@ public class AST2CPPTests extends AST2BaseTest {
|
|||
assertSame(fc, ref);
|
||||
bh.assertNonProblem("g(0 ? p : \"\")", 1); //
|
||||
}
|
||||
|
||||
// struct C {
|
||||
// C();
|
||||
// C(int a, int b);
|
||||
// };
|
||||
//
|
||||
// C c1; // C()
|
||||
// C c2(1,2); // C(int, int)
|
||||
// C c3 ({1,2}); // C(C(int, int)) // copy ctor is elided
|
||||
// C c4 ={1,2}; // C(C(int, int)) // copy ctor is elided
|
||||
// C c5 {1,2}; // C(int, int)
|
||||
public void testCtorForAutomaticVariables_156668() throws Exception {
|
||||
String code= getAboveComment();
|
||||
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
|
||||
IFunction ctor1= bh.assertNonProblem("C();", 1);
|
||||
IFunction ctor2= bh.assertNonProblem("C(int a, int b);", 1);
|
||||
|
||||
IASTName name;
|
||||
IASTImplicitNameOwner dtor;
|
||||
name= bh.findName("c1", 2);
|
||||
dtor= (IASTImplicitNameOwner) name.getParent();
|
||||
assertSame(ctor1, dtor.getImplicitNames()[0].resolveBinding());
|
||||
name= bh.findName("c2", 2);
|
||||
dtor= (IASTImplicitNameOwner) name.getParent();
|
||||
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
|
||||
name= bh.findName("c3", 2);
|
||||
dtor= (IASTImplicitNameOwner) name.getParent();
|
||||
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
|
||||
name= bh.findName("c4", 2);
|
||||
dtor= (IASTImplicitNameOwner) name.getParent();
|
||||
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
|
||||
name= bh.findName("c5", 2);
|
||||
dtor= (IASTImplicitNameOwner) name.getParent();
|
||||
assertSame(ctor2, dtor.getImplicitNames()[0].resolveBinding());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -196,6 +196,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
|
||||
|
@ -2399,7 +2400,14 @@ public class CPPSemantics {
|
|||
((FunctionSetType) iType).applySelectedFunction(bestFnCost.getCost(i).getSelectedFunction());
|
||||
}
|
||||
}
|
||||
return bestFnCost.getFunction();
|
||||
IFunction result= bestFnCost.getFunction();
|
||||
if (bestFnCost.isDirectInitWithCopyCtor()) {
|
||||
Cost c0= bestFnCost.getCost(0);
|
||||
IFunction firstConversion= c0.getUserDefinedConversion();
|
||||
if (firstConversion instanceof ICPPConstructor)
|
||||
return firstConversion;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void setTargetedFunctionsToUnknown(IType[] argTypes) {
|
||||
|
@ -2450,8 +2458,8 @@ public class CPPSemantics {
|
|||
if (iast != i) {
|
||||
fns[i]= fns[iast];
|
||||
fns[iast]= fn;
|
||||
iast++;
|
||||
}
|
||||
iast++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2545,9 +2553,10 @@ public class CPPSemantics {
|
|||
|
||||
Context ctx= Context.ORDINARY;
|
||||
if (j==0 && sourceLen == 1 && fn instanceof ICPPConstructor) {
|
||||
if (paramType instanceof ICPPReferenceType && !((ICPPReferenceType) paramType).isRValueReference()) {
|
||||
if (paramType instanceof ICPPReferenceType) {
|
||||
if (((ICPPConstructor) fn).getClassOwner().isSameType(getNestedType(paramType, TDEF|REF|CVTYPE))) {
|
||||
ctx= Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR;
|
||||
result.setIsDirectInitWithCopyCtor(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2940,7 +2949,8 @@ public class CPPSemantics {
|
|||
IASTDeclarator dtor= ASTQueries.findOutermostDeclarator(declarator);
|
||||
IASTNode parent = dtor.getParent();
|
||||
if (parent instanceof IASTSimpleDeclaration) {
|
||||
if (dtor.getInitializer() == null) {
|
||||
final IASTInitializer initializer = dtor.getInitializer();
|
||||
if (initializer == null) {
|
||||
IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier();
|
||||
parent = parent.getParent();
|
||||
if (parent instanceof IASTCompositeTypeSpecifier ||
|
||||
|
@ -2950,7 +2960,7 @@ public class CPPSemantics {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
return findImplicitlyCalledConstructor(declarator.getName(), dtor.getInitializer());
|
||||
return findImplicitlyCalledConstructor(declarator.getName(), initializer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -2976,10 +2986,12 @@ public class CPPSemantics {
|
|||
type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE);
|
||||
if (!(type instanceof ICPPClassType))
|
||||
return null;
|
||||
final ICPPClassType classType = (ICPPClassType) type;
|
||||
if (type instanceof ICPPClassTemplate || type instanceof ICPPUnknownClassType || type instanceof IProblemBinding)
|
||||
return null;
|
||||
|
||||
// Copy initialization
|
||||
final ICPPClassType classType = (ICPPClassType) type;
|
||||
if (initializer instanceof IASTEqualsInitializer) {
|
||||
// Copy initialization
|
||||
IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer;
|
||||
IASTInitializerClause initClause = eqInit.getInitializerClause();
|
||||
IType sourceType= null;
|
||||
|
@ -2994,35 +3006,47 @@ public class CPPSemantics {
|
|||
if (sourceType != null) {
|
||||
Cost c= Conversions.checkImplicitConversionSequence(type, sourceType, isLValue, UDCMode.ALLOWED, Context.ORDINARY);
|
||||
if (c.converts()) {
|
||||
IFunction f= c.getUserDefinedConversion();
|
||||
if (f instanceof ICPPConstructor)
|
||||
return (ICPPConstructor) f;
|
||||
ICPPFunction f = c.getUserDefinedConversion();
|
||||
if (f instanceof ICPPConstructor)
|
||||
return (ICPPConstructor) f;
|
||||
// If a conversion is used, the constructor is elided.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else if (initializer instanceof ICPPASTInitializerList) {
|
||||
// List initialization
|
||||
final InitializerListType listType = new InitializerListType((ICPPASTInitializerList) initializer);
|
||||
Cost c= Conversions.listInitializationSequence(listType, type, UDCMode.ALLOWED, true);
|
||||
if (c.converts()) {
|
||||
ICPPFunction f = c.getUserDefinedConversion();
|
||||
if (f instanceof ICPPConstructor)
|
||||
return (ICPPConstructor) f;
|
||||
}
|
||||
} 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);
|
||||
|
||||
// Direct Initialization
|
||||
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);
|
||||
if (initializer == null) {
|
||||
data.setFunctionArguments(false);
|
||||
} else if (initializer instanceof ICPPASTConstructorInitializer) {
|
||||
data.setFunctionArguments(false, ((ICPPASTConstructorInitializer) initializer).getArguments());
|
||||
} else {
|
||||
LookupData data = new LookupData(astName);
|
||||
data.setFunctionArguments(false, arguments);
|
||||
data.forceQualified = true;
|
||||
data.foundItems = classType.getConstructors();
|
||||
binding = resolveAmbiguities(data, astName);
|
||||
if (binding instanceof ICPPConstructor)
|
||||
return (ICPPConstructor) binding;
|
||||
} else if (initializer == null) {
|
||||
// Default initialization
|
||||
ICPPConstructor[] ctors = classType.getConstructors();
|
||||
for (ICPPConstructor ctor : ctors) {
|
||||
if (ctor.getRequiredArgumentCount() == 0)
|
||||
return ctor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
data.forceQualified = true;
|
||||
data.foundItems = classType.getConstructors();
|
||||
binding = resolveAmbiguities(data, astName);
|
||||
if (binding instanceof ICPPConstructor)
|
||||
return (ICPPConstructor) binding;
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -85,32 +85,42 @@ public class Conversions {
|
|||
public static Cost checkImplicitConversionSequence(IType target, IType exprType,
|
||||
ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException {
|
||||
final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT;
|
||||
if (isImpliedObject) {
|
||||
if (isImpliedObject)
|
||||
udc= UDCMode.FORBIDDEN;
|
||||
}
|
||||
|
||||
target= getNestedType(target, TDEF);
|
||||
exprType= getNestedType(exprType, TDEF | REF);
|
||||
final IType cv1T1= getNestedType(target, TDEF | REF);
|
||||
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
|
||||
|
||||
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
|
||||
if (target instanceof ICPPReferenceType) {
|
||||
// [8.5.3-5] initialization of a reference
|
||||
final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference();
|
||||
final IType cv1T1= getNestedType(target, TDEF | REF);
|
||||
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
|
||||
final IType cv2T2= exprType;
|
||||
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ);
|
||||
|
||||
// mstodo: will change when implementing rvalue references on this pointer
|
||||
final boolean isImplicitWithoutRefQualifier = isImpliedObject;
|
||||
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
|
||||
if (!isImplicitWithoutRefQualifier) {
|
||||
if (isLValueRef) {
|
||||
refBindingType= ReferenceBinding.LVALUE_REF;
|
||||
} else if (valueCat == LVALUE) {
|
||||
} else {
|
||||
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (exprType instanceof InitializerListType) {
|
||||
if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.c)
|
||||
return Cost.NO_CONVERSION;
|
||||
|
||||
Cost cost= listInitializationSequence(((InitializerListType) exprType), T1, udc, false);
|
||||
if (cost.converts()) {
|
||||
cost.setReferenceBinding(refBindingType);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
// If the reference is an lvalue reference and ...
|
||||
if (isLValueRef) {
|
||||
// ... the initializer expression is an lvalue (but is not a bit field)
|
||||
|
@ -237,23 +247,11 @@ public class Conversions {
|
|||
}
|
||||
|
||||
// Non-reference binding
|
||||
IType uqsource= getNestedType(exprType, TDEF | REF | ALLCVQ);
|
||||
IType uqtarget= getNestedType(target, TDEF | REF | ALLCVQ);
|
||||
|
||||
// [13.3.3.1-6] Derived to base conversion
|
||||
if (uqsource instanceof ICPPClassType && uqtarget instanceof ICPPClassType) {
|
||||
int depth= SemanticUtil.calculateInheritanceDepth(uqsource, uqtarget);
|
||||
if (depth > -1) {
|
||||
if (depth == 0) {
|
||||
return new Cost(uqsource, uqtarget, Rank.IDENTITY);
|
||||
}
|
||||
Cost cost= new Cost(uqsource, uqtarget, Rank.CONVERSION);
|
||||
cost.setInheritanceDistance(depth);
|
||||
return cost;
|
||||
}
|
||||
Cost cost= nonReferenceConversion(valueCat, exprType, T1, udc, isImpliedObject);
|
||||
if (cost.converts()) {
|
||||
cost.setReferenceBinding(refBindingType);
|
||||
}
|
||||
|
||||
return nonReferenceConversion(valueCat, exprType, uqtarget, udc, isImpliedObject);
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,7 +312,7 @@ public class Conversions {
|
|||
if (uqTarget instanceof ICPPClassType) {
|
||||
if (uqSource instanceof ICPPClassType) {
|
||||
// 13.3.3.1-6 Conceptual derived to base conversion
|
||||
int depth= calculateInheritanceDepth(uqTarget, uqSource);
|
||||
int depth= calculateInheritanceDepth(uqSource, uqTarget);
|
||||
if (depth >= 0) {
|
||||
if (depth == 0) {
|
||||
return new Cost(source, target, Rank.IDENTITY);
|
||||
|
|
|
@ -74,6 +74,10 @@ public class Cost {
|
|||
public void setCouldNarrow() {
|
||||
assert false;
|
||||
}
|
||||
@Override
|
||||
public void setSelectedFunction(ICPPFunction function) {
|
||||
assert false;
|
||||
}
|
||||
};
|
||||
|
||||
IType source;
|
||||
|
@ -110,6 +114,11 @@ public class Cost {
|
|||
fRank= rank;
|
||||
}
|
||||
|
||||
|
||||
public ReferenceBinding getReferenceBinding() {
|
||||
return fReferenceBinding;
|
||||
}
|
||||
|
||||
public void setReferenceBinding(ReferenceBinding binding) {
|
||||
fReferenceBinding= binding;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class FunctionCost {
|
|||
private final IFunction fFunction;
|
||||
private final Cost[] fCosts;
|
||||
private final ValueCategory[] fValueCategories;
|
||||
private boolean fIsDirectCopyCtor;
|
||||
|
||||
public FunctionCost(IFunction fn, int paramCount) {
|
||||
fFunction= fn;
|
||||
|
@ -109,6 +110,7 @@ class FunctionCost {
|
|||
if (!udcCost.converts()) {
|
||||
return false;
|
||||
}
|
||||
udcCost.setReferenceBinding(cost.getReferenceBinding());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -212,4 +214,12 @@ class FunctionCost {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setIsDirectInitWithCopyCtor(boolean val) {
|
||||
fIsDirectCopyCtor= val;
|
||||
}
|
||||
|
||||
public boolean isDirectInitWithCopyCtor() {
|
||||
return fIsDirectCopyCtor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2009 Wind River Systems, Inc. and others.
|
||||
* Copyright (c) 2006, 2010 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
|
||||
|
@ -293,7 +293,7 @@ public class BasicCppCallHierarchyTest extends CallHierarchyBaseTest {
|
|||
// void automatic() {
|
||||
// MyClass m;
|
||||
// }
|
||||
public void _testAutomaticConstructor_156668() throws Exception {
|
||||
public void testAutomaticConstructor_156668() throws Exception {
|
||||
String content = readTaggedComment("testAutomaticConstructor");
|
||||
IFile file= createFile(getProject(), "testConstructor.cpp", content);
|
||||
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
|
@ -304,6 +304,15 @@ public class BasicCppCallHierarchyTest extends CallHierarchyBaseTest {
|
|||
Tree tree = getCHTreeViewer().getTree();
|
||||
checkTreeNode(tree, 0, "MyClass::MyClass()");
|
||||
checkTreeNode(tree, 0, 0, "automatic()");
|
||||
}
|
||||
|
||||
public void _testAutomaticDestructor_156668() throws Exception {
|
||||
String content = readTaggedComment("testAutomaticConstructor");
|
||||
IFile file= createFile(getProject(), "testConstructor.cpp", content);
|
||||
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
CEditor editor = openEditor(file);
|
||||
openCallHierarchy(editor);
|
||||
Tree tree = getCHTreeViewer().getTree();
|
||||
|
||||
editor.selectAndReveal(content.indexOf("~MyClass"), 2);
|
||||
openCallHierarchy(editor);
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.eclipse.cdt.core.index.IIndexName;
|
|||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
|
||||
|
||||
/**
|
||||
|
@ -1991,6 +1992,8 @@ public class SemanticHighlightings {
|
|||
&& ((ICPPMethod) binding).isImplicit()) {
|
||||
return false;
|
||||
}
|
||||
if (binding instanceof ICPPUnknownBinding)
|
||||
return false;
|
||||
char[] chars = name.toCharArray();
|
||||
if (chars[0] == '~' || OverloadableOperator.isNew(chars)
|
||||
|| OverloadableOperator.isDelete(chars)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue