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:
parent
a736d7bf98
commit
b23fa116f6
8 changed files with 304 additions and 67 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue