1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-13 03:55:22 +02:00

Bug 415394 - Function parameter types allowing implicit conversion from

other types should not be forward-declared
This commit is contained in:
Sergey Prigogin 2013-08-19 20:35:48 -07:00
parent c9a53b072d
commit b7d7630bda
2 changed files with 98 additions and 32 deletions

View file

@ -291,6 +291,21 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
assertDeclared("A"); assertDeclared("A");
} }
// struct A {
// A(const char* s);
// };
// struct B {
// explicit B(const char* s);
// };
// void f(A a, B b);
public void testFunctionDeclarationWithTypeConversion() throws Exception {
// A file declaring the function is responsible for defining the parameter type that
// provides constructor that can be used for implicit conversion.
assertDefined("A");
assertDeclared("B");
}
// struct A {}; // struct A {};
// struct B {}; // struct B {};

View file

@ -55,7 +55,6 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
@ -68,6 +67,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IParameter; import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding;
@ -87,6 +87,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
@ -98,6 +99,7 @@ import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions;
@ -211,7 +213,7 @@ public class BindingClassifier {
} }
/** /**
* Returns {@code true} if {@code targetType} has a constructor that can be used for * Returns {@code true} if the {@code classType} has a constructor that can be used for
* implicit conversion from {@code argument}. * implicit conversion from {@code argument}.
*/ */
private boolean hasConvertingConstructor(ICPPClassType classType, IASTInitializerClause argument) { private boolean hasConvertingConstructor(ICPPClassType classType, IASTInitializerClause argument) {
@ -235,6 +237,30 @@ public class BindingClassifier {
return false; return false;
} }
/**
* Returns {@code true} if {@code classType} has a constructor that can be used for
* implicit conversion from some other type.
*/
private boolean hasConvertingConstructor(ICPPClassType classType, IASTNode point) {
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(classType, point);
for (ICPPConstructor constructor : constructors) {
if (!constructor.isExplicit()) {
ICPPParameter[] parameters = constructor.getParameters();
if (parameters.length != 0 && CPPFunction.getRequiredArgumentCount(parameters) <= 1) {
IType type = getNestedType(parameters[0].getType(), REF | ALLCVQ);
if (!classType.isSameType(type))
return true;
}
}
}
return false;
}
private boolean isTypeWithConvertingConstructor(IType type, IASTNode point) {
type = getNestedType(type, REF | ALLCVQ);
return type instanceof ICPPClassType && hasConvertingConstructor((ICPPClassType) type, point);
}
/** /**
* Resolves the given binding and returns the binding(s) which we actually have to either * Resolves the given binding and returns the binding(s) which we actually have to either
* declare or define. As an example, if the given binding is a variable, this function returns * declare or define. As an example, if the given binding is a variable, this function returns
@ -519,7 +545,7 @@ public class BindingClassifier {
if (!staticMember) { if (!staticMember) {
for (IASTDeclarator declarator : declarators) { for (IASTDeclarator declarator : declarators) {
if (!(declarator instanceof IASTFunctionDeclarator) && if (!(declarator instanceof IASTFunctionDeclarator) &&
declarator.getPointerOperators().equals(IASTPointerOperator.EMPTY_ARRAY)) { declarator.getPointerOperators().length == 0) {
canBeDeclared = false; canBeDeclared = false;
break; break;
} }
@ -531,7 +557,13 @@ public class BindingClassifier {
defineBindingForName(name); defineBindingForName(name);
} }
} }
} else if (declaration instanceof IASTFunctionDefinition) { }
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator) {
/* /*
* The type specifier of a function definition doesn't need to be defined if it is * The type specifier of a function definition doesn't need to be defined if it is
* a pointer or reference type. * a pointer or reference type.
@ -542,24 +574,59 @@ public class BindingClassifier {
* Example 2: * Example 2:
* X& foo() { } // definition of X is not required here * X& foo() { } // definition of X is not required here
*/ */
IBinding binding = ((IASTFunctionDefinition) declaration).getDeclarator().getName().resolveBinding(); IBinding binding = declarator.getName().resolveBinding();
if (binding instanceof IFunction) { if (binding instanceof IFunction) {
IFunction function = (IFunction) binding; IFunction function = (IFunction) binding;
// Define the return type if necessary IFunctionType functionType = function.getType();
IType returnType = function.getType().getReturnType(); if (declarator.getPropertyInParent() == IASTFunctionDefinition.DECLARATOR) {
if (!(returnType instanceof IPointerType) && !(returnType instanceof ICPPReferenceType)) { // Define the return type if necessary.
defineTypeExceptTypedefOrNonFixedEnum(returnType); IType returnType = functionType.getReturnType();
} if (!(returnType instanceof IPointerType) && !(returnType instanceof ICPPReferenceType)) {
defineTypeExceptTypedefOrNonFixedEnum(returnType);
// Define parameter types if necessary }
IType[] parameterTypes = function.getType().getParameterTypes();
for (IType type : parameterTypes) { // Define parameter types if necessary.
if (!(type instanceof IPointerType) && !(type instanceof ICPPReferenceType)) { IType[] parameterTypes = functionType.getParameterTypes();
defineTypeExceptTypedefOrNonFixedEnum(type); for (IType type : parameterTypes) {
if (!(type instanceof IPointerType)) {
if (!(type instanceof ICPPReferenceType) ||
isTypeWithConvertingConstructor(type, declarator)) {
defineTypeExceptTypedefOrNonFixedEnum(type);
}
}
}
} else {
// As a matter of policy, a function declaration is responsible for
// providing definitions of parameter types that have implicit converting
// constructors.
IType[] parameterTypes = functionType.getParameterTypes();
for (IType type : parameterTypes) {
if (!(type instanceof IPointerType)) {
if (isTypeWithConvertingConstructor(type, declarator)) {
defineTypeExceptTypedefOrNonFixedEnum(type);
}
}
} }
} }
} }
}
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
/*
* The type specifier of an elaborated type neither needs to be defined nor needs to be
* declared. This is because an elaborated type specifier is a self-sufficient
* statement.
*
* Example:
* class X; // neither definition nor declaration of X is required here
*/
return PROCESS_SKIP;
} }
return PROCESS_CONTINUE; return PROCESS_CONTINUE;
} }
@ -679,22 +746,6 @@ public class BindingClassifier {
return PROCESS_CONTINUE; return PROCESS_CONTINUE;
} }
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
/*
* The type specifier of an elaborated type neither needs to be defined nor needs to be
* declared. This is because an elaborated type specifier is a self-sufficient
* statement.
*
* Example:
* class X; // neither definition nor declaration of X is required here
*/
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
@Override @Override
public int visit(IASTStatement statement) { public int visit(IASTStatement statement) {
if (statement instanceof IASTReturnStatement) { if (statement instanceof IASTReturnStatement) {