1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

238232: fix conversions relating to implicit object argument, and some follow on exposed bugs

This commit is contained in:
Andrew Ferguson 2008-06-26 10:06:52 +00:00
parent a736d7bf98
commit b23fa116f6
8 changed files with 304 additions and 67 deletions

View file

@ -5795,4 +5795,120 @@ public class AST2CPPTests extends AST2BaseTest {
ICPPFunction fn2= bh.assertNonProblem("func(&C::m2", 4, ICPPFunction.class);
assertNotSame(fn1, fn2);
}
// class A;
//
// void foo(A* a) {}
// void foo(const A* a) {}
// void foo(volatile A* a) {}
// void foo(const volatile A* a) {}
//
// class A {
// public:
// void member1() { foo(this);/*1*/ }
// void member2() const { foo(this);/*2*/ }
// void member3() volatile { foo(this);/*3*/ }
// void member4() const volatile { foo(this);/*4*/ }
// };
public void testThisType() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
ICPPFunction pt1= ba.assertNonProblem("foo(this);/*1*/", 3, ICPPFunction.class);
ICPPFunction pt2= ba.assertNonProblem("foo(this);/*2*/", 3, ICPPFunction.class);
ICPPFunction pt3= ba.assertNonProblem("foo(this);/*3*/", 3, ICPPFunction.class);
ICPPFunction pt4= ba.assertNonProblem("foo(this);/*4*/", 3, ICPPFunction.class);
IType t1= ((IPointerType)pt1.getType().getParameterTypes()[0]).getType();
IQualifierType t2= (IQualifierType) ((IPointerType) pt2.getType().getParameterTypes()[0]).getType();
IQualifierType t3= (IQualifierType)((IPointerType) pt3.getType().getParameterTypes()[0]).getType();
IQualifierType t4= (IQualifierType)((IPointerType) pt4.getType().getParameterTypes()[0]).getType();
assertTrue(!(t1 instanceof IQualifierType));
assertTrue(t2.isConst()); assertTrue(!t2.isVolatile());
assertTrue(!t3.isConst()); assertTrue(t3.isVolatile());
assertTrue(t4.isConst()); assertTrue(t4.isVolatile());
}
// class A {
// public:
// void foo() {}
// };
//
// void ref() {
// A a1= *new A();
// a1->foo();/*1*/
// A* a2= new A();
// a2->foo();/*2*/
// }
public void testMemberAccessOperator_a() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
ba.assertProblem("foo();/*1*/", 3);
ba.assertNonProblem("foo();/*2*/", 3);
}
// class A {
// public:
// void foo() {};
// };
//
// class B {
// public:
// void foo() {};
// A* operator->() {return new A();}
// };
//
// void ref() {
// B b= *new B();
// b->foo();/*1*/
// B* b2= new B();
// b2->foo();/*2*/
// }
public void testMemberAccessOperator_b() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
ICPPMethod m1= ba.assertNonProblem("foo();/*1*/", 3, ICPPMethod.class);
ICPPMethod m2= ba.assertNonProblem("foo();/*2*/", 3, ICPPMethod.class);
assertEquals(m1.getClassOwner().getName(), "A");
assertEquals(m2.getClassOwner().getName(), "B");
}
// class A { public: void foo(); };
// class B { public: A* operator->() {return new A();} };
// class C { public: B operator->() {return *new B();} };
//
// void ref() {
// C c;
// c->foo();/**/ // refers to A::foo
// }
public void testMemberAccessOperator_c() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertNonProblem("foo();/**/", 3);
}
// class A { public: void foo(); };
// class B { public: A* operator->() {return new A();} };
// class C { public: B* operator->() {return new B();} };
//
// void ref() {
// C c;
// c->foo();/**/ // expect problem - foo is not in B
// }
public void testMemberAccessOperator_d() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertProblem("foo();/**/", 3);
}
// class A { public: void foo(); };
// typedef A A2;
// class B { public: A2* operator->() {return new A();} };
// typedef B B2;
// class C { public: B2 operator->() {return *new B();} };
//
// typedef C C2;
// void ref() {
// C2 c;
// c->foo();/**/ // refers to A::foo
// }
public void testMemberAccessOperator_e() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertNonProblem("foo();/**/", 3);
}
}

View file

@ -2970,4 +2970,54 @@ public class AST2TemplateTests extends AST2BaseTest {
ICPPSpecialization ctps= ba.assertNonProblem("C<A,5L>", 7, ICPPSpecialization.class, ICPPClassType.class);
assertFalse(ctps instanceof ICPPTemplateInstance);
}
// class A {
// public:
// A(const A& a) {}
// };
//
// template<typename T>
// class B : A {
// public:
// B(const B<T>& other) : A(other) {}
// };
public void testChainInitializerLookupThroughDeferredClassBase() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertNonProblem("A(other", 1);
}
// class A {};
//
// class B {
// public:
// void foo(const A& b);
// };
//
// template<typename T>
// class C : public B {
// public:
// void foo(T *t) {
// B::foo(static_cast<A*>(t));
// }
// };
public void testMemberLookupThroughDeferredClassBase() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertNonProblem("foo(s", 3);
}
// template <class T>
// class A {
// public:
// inline int foo() const;
// inline int bar() const;
// };
//
// template <class T>
// inline int A<T>::bar() const {
// return foo();
// }
public void testMemberReferenceFromTemplatedMethodDefinition_238232() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
ba.assertNonProblem("foo();", 3);
}
}

View file

@ -1275,7 +1275,7 @@ public class CompleteParser2Tests extends BaseTestCase {
buff.append( " void f_SD_01(); \n"); //$NON-NLS-1$
buff.append( "}; \n"); //$NON-NLS-1$
buff.append( "int main(){ \n"); //$NON-NLS-1$
buff.append( " SD_01 a = new SD_01(); \n"); //$NON-NLS-1$ // REFERENCE SD_01 * 2
buff.append( " SD_01* a = new SD_01(); \n"); //$NON-NLS-1$ // REFERENCE SD_01 * 2
buff.append( " a->f_SD_01(); \n"); //$NON-NLS-1$ // REFERENCE a && REFERENCE f_SD_01
buff.append( "} \n"); //$NON-NLS-1$
buff.append( "void SD_01::f_SD_01() \n"); //$NON-NLS-1$ // REFERENCE SD_01

View file

@ -15,6 +15,7 @@
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers;
import java.util.ArrayList;
import java.util.HashMap;
@ -61,7 +62,9 @@ import org.eclipse.cdt.core.dom.ast.IEnumerator;
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;
import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
@ -126,6 +129,8 @@ import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference;
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.CPPASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
@ -138,6 +143,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDirective;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalTemplateInstantiator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@ -2372,6 +2378,80 @@ public class CPPSemantics {
}
return result;
}
/**
* For a pointer dereference expression e1->e2, return the type that e1 ultimately evaluates to
* when chaining overloaded class member access operators <code>operator->()</code> calls.
* @param fieldReference
* @return the type the field owner expression ultimately evaluates to when chaining overloaded
* class member access operators <code>operator->()</code> calls.
* @throws DOMException
*/
public static IType getChainedMemberAccessOperatorReturnType(ICPPASTFieldReference fieldReference) throws DOMException {
IASTExpression owner = fieldReference.getFieldOwner();
IType result= CPPVisitor.getExpressionType(owner);
if (fieldReference.isPointerDereference()) {
IType type= getUltimateTypeUptoPointers(result);
boolean needCheckClassMemberAccessOperator= true;
if(type instanceof IPointerType) {
type= getUltimateTypeUptoPointers(((IPointerType) type).getType());
if(type instanceof ICPPClassType) {
needCheckClassMemberAccessOperator= false;
}
}
if(needCheckClassMemberAccessOperator) {
IType temp= result;
result= null;
// bug 205964: as long as the type is a class type, recurse.
// Be defensive and allow a max of 10 levels.
for (int j = 0; j < 10; j++) {
IType uTemp= getUltimateTypeUptoPointers(temp);
if (uTemp instanceof ICPPClassType) {
/*
* 13.5.6-1: An expression x->m is interpreted as (x.operator->())->m for a
* class object x of type T
*
* Construct an AST fragment for x.operator-> which the lookup routines can
* examine for type information.
*/
CPPASTName x= new CPPASTName();
boolean isConst= false, isVolatile= false;
if(temp instanceof IQualifierType) {
isConst= ((IQualifierType)temp).isConst();
isVolatile= ((IQualifierType)temp).isVolatile();
}
x.setBinding(createVariable(x, uTemp, isConst, isVolatile));
IASTName arw= new CPPASTName(OverloadableOperator.ARROW.toCharArray());
IASTFieldReference innerFR= new CPPASTFieldReference(arw, new CPPASTIdExpression(x));
innerFR.setParent(fieldReference); // connect to the AST
ICPPFunction op = CPPSemantics.findOperator(innerFR, (ICPPClassType) uTemp);
if (op != null) {
result= temp= op.getType().getReturnType();
continue;
}
}
break;
}
}
}
return result;
}
private static ICPPVariable createVariable(IASTName name, final IType type, final boolean isConst, final boolean isVolatile) {
return new CPPVariable(name) {
@Override public IType getType() {
return new CPPQualifierType(type, isConst, isVolatile);
}
};
}
public static ICPPFunction findOperator(IASTExpression exp, ICPPClassType cls) {
IScope scope = null;
try {

View file

@ -939,24 +939,8 @@ public class CPPVisitor {
}
} else if (parent instanceof ICPPASTFieldReference) {
final ICPPASTFieldReference fieldReference = (ICPPASTFieldReference)parent;
IASTExpression owner = fieldReference.getFieldOwner();
IType type = getExpressionType(owner);
if (fieldReference.isPointerDereference()) {
// bug 205964: as long as the type is a class type, recurse.
// Be defensive and allow a max of 10 levels.
for (int j = 0; j < 10; j++) {
type= getUltimateTypeUptoPointers(type);
if (type instanceof ICPPClassType) {
ICPPFunction op = CPPSemantics.findOperator(fieldReference, (ICPPClassType) type);
if (op != null) {
type = op.getType().getReturnType();
}
} else {
break;
}
}
}
type = getUltimateType(type, false);
IType type = CPPSemantics.getChainedMemberAccessOperatorReturnType(fieldReference);
type= getUltimateType(type, false);
if (type instanceof ICPPClassType) {
return ((ICPPClassType) type).getCompositeScope();
}

View file

@ -43,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
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.index.IIndexFragmentBinding;
import org.eclipse.core.runtime.CoreException;
@ -66,7 +67,9 @@ public class Conversions {
public static Cost checkImplicitConversionSequence(boolean allowUDC, IASTExpression sourceExp, IType source, IType target, boolean isImpliedObject) throws DOMException {
Cost cost;
if (!isImpliedObject && target instanceof ICPPReferenceType) {
allowUDC &= !isImpliedObject;
if (target instanceof ICPPReferenceType) {
// [13.3.3.3.1] Reference binding
IType cv1T1= ((ICPPReferenceType)target).getType();
cost= new Cost(source, cv1T1);
@ -79,6 +82,14 @@ public class Conversions {
/* Direct reference binding */
// [13.3.3.1.4]
if (cost.source.isSameType(cost.target) ||
// 7.3.3.13 for overload resolution the implicit this pointer is treated as if
// it were a pointer to the derived class
(isImpliedObject && cost.source instanceof ICPPClassType && cost.target instanceof ICPPClassType)) {
cost.rank = Cost.IDENTITY_RANK;
return cost;
}
/*
* is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2,"
*/
@ -87,7 +98,8 @@ public class Conversions {
qualificationConversion(cost);
derivedToBaseConversion(cost);
} else if (T2 instanceof ICPPClassType && allowUDC) {
} else if (T2 instanceof ICPPClassType) {
if(allowUDC) {
/*
* or has a class type (i.e., T2 is a class type) and can be implicitly converted to
* an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92)
@ -127,6 +139,7 @@ public class Conversions {
}
}
}
}
/* Direct binding failed */
@ -449,8 +462,11 @@ public class Conversions {
if (maxdepth > 0 && type instanceof ICPPClassType && ancestorToFind instanceof ICPPClassType) {
ICPPClassType clazz = (ICPPClassType) type;
ICPPBase[] bases= clazz.getBases();
for (ICPPBase cppBase : bases) {
if(clazz instanceof ICPPDeferredClassInstance) {
clazz= (ICPPClassType) ((ICPPDeferredClassInstance)clazz).getSpecializedBinding();
}
for (ICPPBase cppBase : clazz.getBases()) {
IBinding base= cppBase.getBaseClass();
if (base instanceof IType) {
IType tbase= (IType) base;

View file

@ -55,8 +55,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
@ -334,18 +332,11 @@ class LookupData {
}
if (prop == IASTFieldReference.FIELD_NAME) {
ICPPASTFieldReference fieldRef = (ICPPASTFieldReference) tempNameParent;
IType implied = CPPVisitor.getExpressionType(fieldRef.getFieldOwner());
IType ultimateImplied= SemanticUtil.getUltimateTypeUptoPointers(implied);
if (fieldRef.isPointerDereference()) {
if (ultimateImplied instanceof ICPPClassType) {
ICPPFunction operator= CPPSemantics.findOperator(fieldRef, (ICPPClassType) ultimateImplied);
if (operator!=null) {
return operator.getType().getReturnType();
}
} else if (implied instanceof IPointerType) {
IType implied= CPPSemantics.getChainedMemberAccessOperatorReturnType(fieldRef);
implied= SemanticUtil.getUltimateTypeUptoPointers(implied);
if (fieldRef.isPointerDereference() && implied instanceof IPointerType) {
return ((IPointerType)implied).getType();
}
}
return implied;
}
if (prop == IASTIdExpression.ID_NAME) {

View file

@ -572,7 +572,7 @@ public class RenameRegressionTests extends RenameTests {
writer = new StringWriter();
writer.write( "#include \"t.hh\" \n" ); //$NON-NLS-1$
writer.write( "void test() { \n" ); //$NON-NLS-1$
writer.write( " Foo d; \n" ); //$NON-NLS-1$
writer.write( " Foo* d; \n" ); //$NON-NLS-1$
writer.write( " d->method1(1); \n" ); //$NON-NLS-1$
writer.write( "} \n" ); //$NON-NLS-1$
String source = writer.toString();