1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-12 19:45: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");
}
// 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 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.IASTNode;
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.IASTPreprocessorMacroExpansion;
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.IEnumeration;
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.IPointerType;
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.ICPPMethod;
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.ICPPSpecialization;
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.cpp.CPPASTIdExpression;
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.semantics.CPPSemantics;
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}.
*/
private boolean hasConvertingConstructor(ICPPClassType classType, IASTInitializerClause argument) {
@ -235,6 +237,30 @@ public class BindingClassifier {
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
* 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) {
for (IASTDeclarator declarator : declarators) {
if (!(declarator instanceof IASTFunctionDeclarator) &&
declarator.getPointerOperators().equals(IASTPointerOperator.EMPTY_ARRAY)) {
declarator.getPointerOperators().length == 0) {
canBeDeclared = false;
break;
}
@ -531,7 +557,13 @@ public class BindingClassifier {
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
* a pointer or reference type.
@ -542,24 +574,59 @@ public class BindingClassifier {
* Example 2:
* 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) {
IFunction function = (IFunction) binding;
// Define the return type if necessary
IType returnType = function.getType().getReturnType();
if (!(returnType instanceof IPointerType) && !(returnType instanceof ICPPReferenceType)) {
defineTypeExceptTypedefOrNonFixedEnum(returnType);
}
// Define parameter types if necessary
IType[] parameterTypes = function.getType().getParameterTypes();
for (IType type : parameterTypes) {
if (!(type instanceof IPointerType) && !(type instanceof ICPPReferenceType)) {
defineTypeExceptTypedefOrNonFixedEnum(type);
IFunctionType functionType = function.getType();
if (declarator.getPropertyInParent() == IASTFunctionDefinition.DECLARATOR) {
// Define the return type if necessary.
IType returnType = functionType.getReturnType();
if (!(returnType instanceof IPointerType) && !(returnType instanceof ICPPReferenceType)) {
defineTypeExceptTypedefOrNonFixedEnum(returnType);
}
// Define parameter types if necessary.
IType[] parameterTypes = functionType.getParameterTypes();
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;
}
@ -679,22 +746,6 @@ public class BindingClassifier {
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
public int visit(IASTStatement statement) {
if (statement instanceof IASTReturnStatement) {