From e4f737f6b10eb8b0d912700b9918443f095e397e Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Wed, 16 Apr 2008 16:04:43 +0000 Subject: [PATCH] 222418: apply fix --- .../cdt/core/parser/tests/ast2/AST2Tests.java | 28 +- .../internal/index/tests/IndexNamesTests.java | 20 +- .../parser/cpp/semantics/CPPSemantics.java | 20 +- .../dom/parser/cpp/semantics/CPPVisitor.java | 33 + .../dom/parser/cpp/semantics/Conversions.java | 716 ++++++++++++------ 5 files changed, 576 insertions(+), 241 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index ccde3831cac..470ca867027 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -4243,7 +4243,7 @@ public class AST2Tests extends AST2BaseTest { // f4(vi); // f4(cvi); // } - public void _testBug222418_a() throws Exception { + public void testBug222418_a() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNonProblem("f1(i)",2); ba.assertProblem("f1(ci)", 2); @@ -4282,7 +4282,7 @@ public class AST2Tests extends AST2BaseTest { // f1(vi); // (3) // f1(cvi); // (4) // } - public void _testBug222418_b() throws Exception { + public void testBug222418_b() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ICPPFunction f1_1= ba.assertNonProblem("f1(i)", 2, ICPPFunction.class); @@ -4326,7 +4326,7 @@ public class AST2Tests extends AST2BaseTest { // fc(five()); // should be an error // fd(five()); // should be an error // } - public void _testBug222418_c() throws Exception { + public void testBug222418_c() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ICPPFunction fn= ba.assertNonProblem("five() {", 4, ICPPFunction.class); @@ -4358,7 +4358,7 @@ public class AST2Tests extends AST2BaseTest { // f_const(2); // ok // f_nonconst(2); // should be an error // } - public void _testBug222418_d() throws Exception { + public void testBug222418_d() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNonProblem("f_const(2", 7, ICPPFunction.class); ba.assertProblem("f_nonconst(2", 10); @@ -4397,7 +4397,7 @@ public class AST2Tests extends AST2BaseTest { // f4(vi); // f4(cvi); // } - public void _testBug222418_e() throws Exception { + public void testBug222418_e() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNonProblem("f1(i)",2); ba.assertProblem("f1(ci)", 2); @@ -4472,7 +4472,7 @@ public class AST2Tests extends AST2BaseTest { // // return 0; // } - public void _testBug222418_f() throws Exception { + public void testBug222418_f() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNonProblem("foo1(a)", 4); ba.assertNonProblem("foo2(a)", 4); @@ -4561,7 +4561,7 @@ public class AST2Tests extends AST2BaseTest { // // return ri; // } - public void _testBug222418_j() throws Exception { + public void testBug222418_j() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNonProblem("fi(ri)", 2); @@ -4591,6 +4591,20 @@ public class AST2Tests extends AST2BaseTest { ba.assertProblem("fcpr(rwp)", 4); } + // class A { + // public: + // void foo() {} + // void foo() const {} + // }; + // void ref() { + // A a; + // a.foo(); + // } + public void testBug222418_k() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + ba.assertNonProblem("foo();", 3); + } + // class B {}; // // class C { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java index b089bbf2efb..6ff62bfae84 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java @@ -328,8 +328,8 @@ public class IndexNamesTests extends BaseTestCase { final String name = indexName.toString(); final char c0= name.length() > 0 ? name.charAt(0) : 0; if ((c0 == '_' || c0 == 'r' || c0 == 'w') && indexName.isReference()) { - boolean isRead= name.charAt(0) == 'r'; - boolean isWrite= name.charAt(isRead ? 1 : 0) == 'w'; + boolean isRead= name.charAt(0) == 'r' || name.charAt(0) == 'u'; + boolean isWrite= name.charAt(isRead ? 1 : 0) == 'w' || name.charAt(0) == 'u'; String msg= "i=" + i + ", " + name + ":"; assertEquals(msg, isRead, indexName.isReadAccess()); assertEquals(msg, isWrite, indexName.isWriteAccess()); @@ -346,8 +346,8 @@ public class IndexNamesTests extends BaseTestCase { } } - // int _i, ri, wi, rwi, rfind, ridebug; - // int* rp; int* wp; int* rwp; + // int _i, ri, wi, rwi, rfind, ui; + // int* rp; int* wp; int* rwp; int* up; // int* const rpc= 0; // const int * const rcpc= 0; // const int* cip= &ri; @@ -366,7 +366,7 @@ public class IndexNamesTests extends BaseTestCase { // void fcpcp(int const *const*); // void fcpcr(int const *const&); // - // void test() { + // int test() { // _i; // wi= ri, _i, _i; // expr-list // rwi %= ri; // assignment @@ -378,10 +378,10 @@ public class IndexNamesTests extends BaseTestCase { // while(ri) {_i;}; // switch(ri) {case ri: _i;}; // fi(ri); fp(&rwi); fcp(&ri); - // fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&rwp); fpcp(&rpc); fcpcp(&rcpc); - // fr(rwi); fcr(ri); fpr(&rwi); - // fcpr(&ridebug); fpcr(&rwi); fcpcr(&ri); - // fpr(rwp); fcpr(rwp); fpcr(rp); fcpcr(rp); + // fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&up); fpcp(&rpc); fcpcp(&rcpc); + // fr(rwi); fcr(ri); fpr(&ui); + // fcpr(&ui); fpcr(&rwi); fcpcr(&ri); + // fpr(rwp); fcpr(up); fpcr(rp); fcpcr(rp); // return ri; // } public void testReadWriteFlagsCpp() throws Exception { @@ -390,6 +390,6 @@ public class IndexNamesTests extends BaseTestCase { IFile file= createFile(getProject().getProject(), "test.cpp", content); waitUntilFileIsIndexed(file, 4000); - checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 51); + checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 47); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index aa09a2bc772..34dd6fc9df7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -313,7 +313,7 @@ public class CPPSemantics { return binding; } - static private LookupData createLookupData( IASTName name, boolean considerAssociatedScopes ){ + private static LookupData createLookupData( IASTName name, boolean considerAssociatedScopes ){ LookupData data = new LookupData( name ); IASTNode parent = name.getParent(); @@ -1895,6 +1895,7 @@ public class CPPSemantics { Cost [] bestFnCost = null; //the cost of the best function Cost [] currFnCost = null; //the cost for the current function + IASTExpression sourceExp; IType source = null; //parameter we are called with IType target = null; //function's parameter @@ -1933,9 +1934,13 @@ public class CPPSemantics { for (int j = 0; j < sourceLen; j++) { if (useImplicitObj > 0) { isImpliedObject= j==0; - source = isImpliedObject ? impliedObjectType : sourceParameters[j - 1]; + source= isImpliedObject ? impliedObjectType : sourceParameters[j - 1]; + Object se= isImpliedObject || data.functionParameters.length==0 ? null : data.functionParameters[j - 1]; + sourceExp= se instanceof IASTExpression ? (IASTExpression) se : null; } else { source = sourceParameters[j]; + Object se= data.functionParameters.length==0 ? null : data.functionParameters[j]; + sourceExp= se instanceof IASTExpression ? (IASTExpression) se : null; } if (j < numTargetParams) { @@ -1960,16 +1965,7 @@ public class CPPSemantics { cost = new Cost( source, target ); cost.rank = Cost.IDENTITY_RANK; //exact match, no cost } else { - cost = Conversions.checkStandardConversionSequence( source, target, isImpliedObject); - //12.3-4 At most one user-defined conversion is implicitly applied to - //a single value. (also prevents infinite loop) - if (!data.forUserDefinedConversion && (cost.rank == Cost.NO_MATCH_RANK || - cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) { - Cost udcCost= Conversions.checkUserDefinedConversionSequence( source, target ); - if( udcCost != null ){ - cost = udcCost; - } - } + cost= Conversions.checkImplicitConversionSequence(!data.forUserDefinedConversion, sourceExp, source, target, isImpliedObject); } currFnCost[ j ] = cost; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index ec5f111c02b..1d1b677183c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -2183,4 +2183,37 @@ public class CPPVisitor { } return false; } + + /** + * [3.10] Lvalues and Rvalues + * @param exp + * @return whether the specified expression is an rvalue + */ + static boolean isRValue(IASTExpression exp) { + if(exp instanceof IASTUnaryExpression) { + IASTUnaryExpression ue= (IASTUnaryExpression) exp; + if(ue.getOperator() == IASTUnaryExpression.op_amper) { + return true; + } + } + if(exp instanceof IASTLiteralExpression) + return true; + if(exp instanceof IASTFunctionCallExpression) { + try { + IASTFunctionCallExpression fc= (IASTFunctionCallExpression) exp; + IASTExpression fne= fc.getFunctionNameExpression(); + if(fne instanceof IASTIdExpression) { + IASTIdExpression ide= (IASTIdExpression) fne; + IBinding b= ide.getName().resolveBinding(); + if(b instanceof IFunction) { + IFunctionType tp= ((IFunction)b).getType(); + return !(tp.getReturnType() instanceof ICPPReferenceType); + } + } + } catch(DOMException de) { + // fall-through + } + } + return false; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index 0ca4ff9630d..44fad0b4a7e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -16,6 +16,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.getUltimateTypeViaTypedefs; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; @@ -46,24 +47,259 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; +import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; +import org.eclipse.core.runtime.CoreException; /** - * Routines for calculating the cost of conversions - * - * See - * [conv] 4 - * [over.best.ics] 13.3.3.1. + * Routines for calculating the cost of conversions. */ -class Conversions { +public class Conversions { + /** + * Computes the cost of an implicit conversion sequence + * [over.best.ics] 13.3.3.1 + * + * @param allowUDC whether a user-defined conversion is allowed during the sequence + * @param sourceExp the expression behind the source type + * @param source the source (argument) type + * @param target the target (parameter) type + * @param isImpliedObject + * @return the cost of converting from source to target + * @throws DOMException + */ + public static Cost checkImplicitConversionSequence(boolean allowUDC, IASTExpression sourceExp, IType source, IType target, boolean isImpliedObject) throws DOMException { + Cost cost; + + if(!isImpliedObject && target instanceof ICPPReferenceType) { + // [13.3.3.3.1] Reference binding + IType cv1T1= ((ICPPReferenceType)target).getType(); + cost= new Cost(source, cv1T1); + cost.targetHadReference= true; + + boolean lvalue= sourceExp == null || !CPPVisitor.isRValue(sourceExp); + IType T2= source instanceof IQualifierType ? ((IQualifierType)source).getType() : source; + + if(lvalue && isReferenceCompatible(cv1T1, source)) { + /* Direct reference binding */ + // [13.3.3.1.4] + + /* + * is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” + */ + // [13.3.3.1.4-1] direct binding + // [8.5.3-5] + qualificationConversion(cost); + + derivedToBaseConversion(cost); + } else if(T2 instanceof ICPPClassType && 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) + * (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6) + * and choosing the best one through overload resolution (13.3)). + */ + ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType)T2); + Cost operatorCost= null; + ICPPMethod conv= null; + boolean ambiguousConversionOperator= false; + if( fcns.length > 0 && fcns[0] instanceof IProblemBinding == false ){ + for (final ICPPMethod op : fcns) { + Cost cost2 = checkStandardConversionSequence( op.getType().getReturnType(), target, false ); + if( cost2.rank != Cost.NO_MATCH_RANK ) { + if (operatorCost == null) { + operatorCost= cost2; + conv= op; + } + else { + int cmp= operatorCost.compare(cost2); + if (cmp >= 0) { + ambiguousConversionOperator= cmp == 0; + operatorCost= cost2; + conv= op; + } + } + } + } + } + + if(conv!= null && !ambiguousConversionOperator) { + IType newSource= conv.getType().getReturnType(); + boolean isNewSourceLValue= newSource instanceof ICPPReferenceType; + if(isNewSourceLValue && isReferenceCompatible(cv1T1, newSource)) { + cost= new Cost(cv1T1, newSource); + qualificationConversion(cost); + derivedToBaseConversion(cost); + } + } + } + + /* Direct binding failed */ + + if(cost.rank == Cost.NO_MATCH_RANK) { + // 8.5.3-5 - Otherwise + + boolean cv1isConst= false; + if(cv1T1 instanceof IQualifierType) { + cv1isConst= ((IQualifierType)cv1T1).isConst() && !((IQualifierType)cv1T1).isVolatile(); + } else if(cv1T1 instanceof IPointerType) { + cv1isConst= ((IPointerType)cv1T1).isConst() && !((IPointerType)cv1T1).isVolatile(); + } + + if(cv1isConst) { + if(!lvalue && source instanceof ICPPClassType) { + cost= new Cost(source, target); + cost.rank= Cost.IDENTITY_RANK; + } else { + // 5 - Otherwise + // Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression + // using the rules for a non-reference copy initialization (8.5). The reference is then bound to the temporary. + + // If T1 is reference-related to T2, cv1 must be the same cv-qualification as, or greater cvqualification + // than, cv2; otherwise, the program is ill-formed. [Example + boolean illformed= false; + if(isReferenceRelated(cv1T1, source)) { + Integer cmp= compareQualifications(cv1T1, source); + if(cmp == null || cmp < 0) { + illformed= true; + } + } + + // we must do a non-reference initialization + if(!illformed) { + cost= checkStandardConversionSequence( source, cv1T1, isImpliedObject); + // 12.3-4 At most one user-defined conversion is implicitly applied to + // a single value. (also prevents infinite loop) + if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK || + cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) { + Cost temp = checkUserDefinedConversionSequence(source, cv1T1); + if( temp != null ){ + cost = temp; + } + } + } + } + } + } + } else { + // Non-reference binding + + cost= checkStandardConversionSequence( source, target, isImpliedObject); + if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK || + cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) { + Cost temp = checkUserDefinedConversionSequence(source, target); + if( temp != null ){ + cost = temp; + } + } + } + + return cost; + } /** + * [3.9.3-4] Implements cv-ness (partial) comparison. There is a (partial) + * ordering on cv-qualifiers, so that a type can be said to be more + * cv-qualified than another. + * @param cv1 + * @param cv2 + * @return + * @throws DOMException + */ + private static final Integer compareQualifications(IType cv1, IType cv2) throws DOMException { + boolean cv1Const= false, cv2Const= false, cv1Volatile= false, cv2Volatile= false; + if(cv1 instanceof IQualifierType) { + IQualifierType qt1= (IQualifierType) cv1; + cv1Const= qt1.isConst(); + cv1Volatile= qt1.isVolatile(); + } else if(cv1 instanceof IPointerType) { + IPointerType pt1= (IPointerType) cv1; + cv1Const= pt1.isConst(); + cv1Volatile= pt1.isVolatile(); + } + if(cv2 instanceof IQualifierType) { + IQualifierType qt2= (IQualifierType) cv2; + cv2Const= qt2.isConst(); + cv2Volatile= qt2.isVolatile(); + } else if(cv2 instanceof IPointerType) { + IPointerType pt2= (IPointerType) cv2; + cv1Const= pt2.isConst(); + cv1Volatile= pt2.isVolatile(); + } + int cmpConst= cv1Const ? (cv2Const ? 0 : 1) : (!cv2Const ? 0 : -1); + int cmpVolatile= cv1Volatile ? (cv2Volatile ? 0 : 1) : (!cv2Volatile ? 0 : -1); + + if(cmpConst == cmpVolatile) { + return cmpConst; + } else if(cmpConst != 0 && cmpVolatile == 0) { + return cmpConst; + } else if(cmpConst == 0 && cmpVolatile != 0) { + return cmpVolatile; + } + + return null; + } + + /** + * [8.5.3] "cv1 T1" is reference-related to "cv2 T2" if T1 is the same type as T2, or T1 is a base class of T2. + * Note this is not a symmetric relation. + * @param cv1t1 + * @param cv2t2 + * @return whether cv1t1 is reference-related to cv2t2 + * @throws DOMException + */ + private static final boolean isReferenceRelated(IType cv1t1, IType cv2t2) throws DOMException { + // I've not found anything in the spec to justify unrolling cv1t1 or cv1t2 so far + IType t1= SemanticUtil.getUltimateTypeUptoPointers(cv1t1); + IType t2= SemanticUtil.getUltimateTypeUptoPointers(cv2t2); + + // The way cv-qualification is currently modeled means + // we must cope with IPointerType objects separately. + if(t1 instanceof IPointerType && t2 instanceof IPointerType) { + IType ptt1= ((IPointerType)t1).getType(); + IType ptt2= ((IPointerType)t2).getType(); + return ptt1 != null && ptt2 != null ? ptt1.isSameType(ptt2) : ptt1 == ptt2; + } + + t1= t1 instanceof IQualifierType ? ((IQualifierType)t1).getType() : t1; + t2= t2 instanceof IQualifierType ? ((IQualifierType)t2).getType() : t2; + + if(t1 instanceof ICPPClassType && t2 instanceof ICPPClassType) { + return calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, (ICPPClassType) t2, (ICPPClassType) t1) >= 0; + } + + return t1 != null && t2 != null ? t1.isSameType(t2) : t1 == t2; + } + + /** + * [8.5.3] “cv1 T1” is reference-compatible with “cv2 T2” if T1 is reference-related + * to T2 and cv1 is the same cv-qualification as, or greater cv-qualification than, cv2. + * Note this is not a symmetric relation. + * @param cv1t1 + * @param cv2t2 + * @return whether cv1t1 is reference-compatible with cv2t2 + * @throws DOMException + */ + private static final boolean isReferenceCompatible(IType cv1t1, IType cv2t2) throws DOMException { + if(isReferenceRelated(cv1t1, cv2t2)) { + Integer cmp= compareQualifications(cv1t1, cv2t2); + return cmp != null && cmp >= 0; + } + return false; + } + + /** + * [4] Standard Conversions * Computes the cost of using the standard conversion sequence from source to target. * @param isImplicitThis handles the special case when members of different * classes are nominated via using-declarations. In such a situation the derived to * base conversion does not cause any costs. * @throws DOMException */ - static protected Cost checkStandardConversionSequence( IType source, IType target, boolean isImplicitThis) throws DOMException { + protected static final Cost checkStandardConversionSequence( IType source, IType target, boolean isImplicitThis) throws DOMException { Cost cost = lvalue_to_rvalue( source, target ); if( cost.source == null || cost.target == null ){ @@ -119,33 +355,38 @@ class Conversions { return cost; } - static Cost checkUserDefinedConversionSequence( IType source, IType target ) throws DOMException { - Cost constructorCost = null; - Cost operatorCost = null; + /** + * [13.3.3.1.2] User-defined conversions + * @param source + * @param target + * @return + * @throws DOMException + */ + private static final Cost checkUserDefinedConversionSequence(IType source, IType target) throws DOMException { + Cost constructorCost= null; + Cost operatorCost= null; - IType s = getUltimateType( source, true ); - IType t = getUltimateType( target, true ); + IType s= getUltimateType(source, true); + IType t= getUltimateType(target, true); //constructors - if( t instanceof ICPPClassType ){ - ICPPConstructor [] constructors = ((ICPPClassType)t).getConstructors(); - if( constructors.length > 0 ){ - if( constructors.length > 0 && constructors[0] instanceof IProblemBinding == false ){ - LookupData data = new LookupData(); - data.forUserDefinedConversion = true; - data.functionParameters = new IType [] { source }; - IBinding binding = CPPSemantics.resolveFunction( data, constructors ); - if( binding instanceof ICPPConstructor ) { - ICPPConstructor constructor = (ICPPConstructor) binding; - if(!constructor.isExplicit()){ - constructorCost = checkStandardConversionSequence( t, target, false ); - if (constructorCost.rank == Cost.NO_MATCH_RANK) { - constructorCost= null; - } + if (t instanceof ICPPClassType) { + ICPPConstructor [] constructors= ((ICPPClassType)t).getConstructors(); + if (constructors.length > 0 && constructors[0] instanceof IProblemBinding == false) { + LookupData data= new LookupData(); + data.forUserDefinedConversion= true; + data.functionParameters= new IType [] { source }; + IBinding binding = CPPSemantics.resolveFunction( data, constructors ); + if( binding instanceof ICPPConstructor ) { + ICPPConstructor constructor= (ICPPConstructor) binding; + if(!constructor.isExplicit()){ + constructorCost = checkStandardConversionSequence( t, target, false ); + if (constructorCost.rank == Cost.NO_MATCH_RANK) { + constructorCost= null; } + } } } - } } boolean checkConversionOperators= @@ -156,12 +397,12 @@ class Conversions { || s instanceof CPPClassInstance); //conversion operators - boolean ambigousConversionOperator= false; + boolean ambiguousConversionOperator= false; if (checkConversionOperators) { ICPPMethod [] ops = SemanticUtil.getConversionOperators((ICPPClassType)s); - if( ops.length > 0 && ops[0] instanceof IProblemBinding == false ){ + if (ops.length > 0 && ops[0] instanceof IProblemBinding == false) { for (final ICPPMethod op : ops) { - Cost cost = checkStandardConversionSequence( op.getType().getReturnType(), target, false ); + Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false); if( cost.rank != Cost.NO_MATCH_RANK ) { if (operatorCost == null) { operatorCost= cost; @@ -169,7 +410,7 @@ class Conversions { else { int cmp= operatorCost.compare(cost); if (cmp >= 0) { - ambigousConversionOperator= cmp == 0; + ambiguousConversionOperator= cmp == 0; operatorCost= cost; } } @@ -179,7 +420,7 @@ class Conversions { } if (constructorCost != null) { - if (operatorCost == null || ambigousConversionOperator) { + if (operatorCost == null || ambiguousConversionOperator) { constructorCost.userDefined = Cost.USERDEFINED_CONVERSION; constructorCost.rank = Cost.USERDEFINED_CONVERSION_RANK; } @@ -192,7 +433,7 @@ class Conversions { } if (operatorCost != null) { operatorCost.rank = Cost.USERDEFINED_CONVERSION_RANK; - if (ambigousConversionOperator) { + if (ambiguousConversionOperator) { operatorCost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION; } else { @@ -212,14 +453,15 @@ class Conversions { * no inheritance relation * @throws DOMException */ - private static int calculateInheritanceDepth(int maxdepth, ICPPClassType clazz, ICPPClassType ancestorToFind) throws DOMException { - if(clazz == ancestorToFind || clazz.isSameType(ancestorToFind)) + private static final int calculateInheritanceDepth(int maxdepth, ICPPClassType clazz, ICPPClassType ancestorToFind) throws DOMException { + if (clazz == ancestorToFind || clazz.isSameType(ancestorToFind)) { return 0; + } - if(maxdepth>0) { - ICPPBase [] bases = clazz.getBases(); + if (maxdepth>0) { + ICPPBase[] bases= clazz.getBases(); for (ICPPBase cppBase : bases) { - IBinding base = cppBase.getBaseClass(); + IBinding base= cppBase.getBaseClass(); if(base instanceof IType) { IType tbase= (IType) base; if( tbase.isSameType(ancestorToFind) || @@ -242,137 +484,74 @@ class Conversions { return -1; } - static private void conversion( Cost cost ) throws DOMException{ - IType src = cost.source; - IType trg = cost.target; - - cost.conversion = 0; - cost.detail = 0; - - IType[] sHolder= new IType[1], tHolder= new IType[1]; - IType s = getUltimateType( src, sHolder, true ); - IType t = getUltimateType( trg, tHolder, true ); - IType sPrev= sHolder[0], tPrev= tHolder[0]; - - if( src instanceof IBasicType && trg instanceof IPointerType ){ - //4.10-1 an integral constant expression of integer type that evaluates to 0 can be converted to a pointer type - IASTExpression exp = ((IBasicType)src).getValue(); - if( exp instanceof IASTLiteralExpression && - ((IASTLiteralExpression)exp).getKind() == IASTLiteralExpression.lk_integer_constant ) - { - try { - String val = exp.toString().toLowerCase().replace('u', '0'); - val.replace( 'l', '0' ); - if( Integer.decode( val ).intValue() == 0 ){ - cost.rank = Cost.CONVERSION_RANK; - cost.conversion = 1; - } - } catch( NumberFormatException e ) { - } - } - } else if( sPrev instanceof IPointerType ){ - //4.10-2 an rvalue of type "pointer to cv T", where T is an object type can be - //converted to an rvalue of type "pointer to cv void" - if( tPrev instanceof IPointerType && t instanceof IBasicType && ((IBasicType)t).getType() == IBasicType.t_void ){ - cost.rank = Cost.CONVERSION_RANK; - cost.conversion = 1; - cost.detail = 2; - return; - } - //4.10-3 An rvalue of type "pointer to cv D", where D is a class type can be converted - //to an rvalue of type "pointer to cv B", where B is a base class of D. - else if( s instanceof ICPPClassType && tPrev instanceof IPointerType && t instanceof ICPPClassType ){ - int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, (ICPPClassType)s, (ICPPClassType) t ); - cost.rank= ( depth > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; - cost.conversion= ( depth > -1 ) ? depth : 0; - cost.detail= 1; - return; - } - // 4.12 if the target is a bool, we can still convert - else if(!(trg instanceof IBasicType && ((IBasicType)trg).getType() == ICPPBasicType.t_bool)) { - return; - } - } - - if( t instanceof IBasicType && s instanceof IBasicType || s instanceof IEnumeration ){ - //4.7 An rvalue of an integer type can be converted to an rvalue of another integer type. - //An rvalue of an enumeration type can be converted to an rvalue of an integer type. - cost.rank = Cost.CONVERSION_RANK; - cost.conversion = 1; - } else if( trg instanceof IBasicType && ((IBasicType)trg).getType() == ICPPBasicType.t_bool && s instanceof IPointerType ){ - //4.12 pointer or pointer to member type can be converted to an rvalue of type bool - cost.rank = Cost.CONVERSION_RANK; - cost.conversion = 1; - } else if( s instanceof ICPPPointerToMemberType && t instanceof ICPPPointerToMemberType ){ - //4.11-2 An rvalue of type "pointer to member of B of type cv T", where B is a class type, - //can be converted to an rvalue of type "pointer to member of D of type cv T" where D is a - //derived class of B - ICPPPointerToMemberType spm = (ICPPPointerToMemberType) s; - ICPPPointerToMemberType tpm = (ICPPPointerToMemberType) t; - IType st = spm.getType(); - IType tt = tpm.getType(); - if( st != null && tt != null && st.isSameType( tt ) ){ - int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, tpm.getMemberOfClass(), spm.getMemberOfClass()); - cost.rank= ( depth > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; - cost.conversion= ( depth > -1 ) ? depth : 0; - cost.detail= 1; - } - } - } - - static private void derivedToBaseConversion( Cost cost ) throws DOMException { - IType s = getUltimateType( cost.source, true ); - IType t = getUltimateType( cost.target, true ); - - if( cost.targetHadReference && s instanceof ICPPClassType && t instanceof ICPPClassType ){ - int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, (ICPPClassType) s, (ICPPClassType) t); - if(depth > -1){ - cost.rank= Cost.DERIVED_TO_BASE_CONVERSION; - cost.conversion= depth; - } - } - } - /** - * 4.5-1 char, signed char, unsigned char, short int or unsigned short int - * can be converted to int if int can represent all the values of the source - * type, otherwise they can be converted to unsigned int. - * 4.5-2 wchar_t or an enumeration can be converted to the first of the - * following that can hold it: int, unsigned int, long unsigned long. - * 4.5-4 bool can be promoted to int - * 4.6 float can be promoted to double + * [4.1] Lvalue-to-rvalue conversion + * [4.2] array-to-ptr + * [4.3] function-to-ptr + * + * @param source + * @param target + * @return * @throws DOMException */ - static private void promotion( Cost cost ) throws DOMException{ - IType src = cost.source; - IType trg = cost.target; + private static final Cost lvalue_to_rvalue(IType source, IType target) throws DOMException { + Cost cost = new Cost(source, target); - if( src.isSameType( trg ) ) - return; - - if( src instanceof IBasicType && trg instanceof IBasicType ){ - int sType = ((IBasicType)src).getType(); - int tType = ((IBasicType)trg).getType(); - if( ( tType == IBasicType.t_int && ( sType == IBasicType.t_int || //short, long , unsigned etc - sType == IBasicType.t_char || - sType == ICPPBasicType.t_bool || - sType == ICPPBasicType.t_wchar_t || - sType == IBasicType.t_unspecified ) ) || //treat unspecified as int - ( tType == IBasicType.t_double && sType == IBasicType.t_float ) ) - { - cost.promotion = 1; - } - } else if( src instanceof IEnumeration && trg instanceof IBasicType && - ( ((IBasicType)trg).getType() == IBasicType.t_int || - ((IBasicType)trg).getType() == IBasicType.t_unspecified ) ) - { - cost.promotion = 1; + if (!isCompleteType(source)) { + cost.rank= Cost.NO_MATCH_RANK; + return cost; } - cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK; - } + if (source instanceof ICPPReferenceType) { + source= ((ICPPReferenceType) source).getType(); + } + if (target instanceof ICPPReferenceType) { + target= ((ICPPReferenceType) target).getType(); + cost.targetHadReference = true; + } - static private void qualificationConversion( Cost cost ) throws DOMException{ + //4.3 function to pointer conversion + if( target instanceof IPointerType && ((IPointerType)target).getType() instanceof IFunctionType && + source instanceof IFunctionType ) + { + source = new CPPPointerType( source ); + } + //4.2 Array-To-Pointer conversion + else if( target instanceof IPointerType && source instanceof IArrayType ){ + source = new CPPPointerType( ((IArrayType)source).getType() ); + } + + //4.1 if T is a non-class type, the type of the rvalue is the cv-unqualified version of T + if( source instanceof IQualifierType ){ + IType t = ((IQualifierType)source).getType(); + while( t instanceof ITypedef ) + t = ((ITypedef)t).getType(); + if( !(t instanceof ICPPClassType) ){ + source = t; + } + } else if( source instanceof IPointerType && + ( ((IPointerType)source).isConst() || ((IPointerType)source).isVolatile() ) ) + { + IType t= ((IPointerType) source).getType(); + while (t instanceof ITypedef) + t= ((ITypedef) t).getType(); + if (!(t instanceof ICPPClassType)) { + source= new CPPPointerType(t); + } + } + + cost.source = source; + cost.target = target; + + return cost; + } + + /** + * [4.4] Qualifications + * @param cost + * @throws DOMException + */ + private static final void qualificationConversion( Cost cost ) throws DOMException{ boolean canConvert = true; int requiredConversion = Cost.IDENTITY_RANK; @@ -496,66 +675,179 @@ class Conversions { } } - static private Cost lvalue_to_rvalue( IType source, IType target ) throws DOMException{ - Cost cost = new Cost( source, target ); + /** + * [4.5] [4.6] Promotion + * + * 4.5-1 char, signed char, unsigned char, short int or unsigned short int + * can be converted to int if int can represent all the values of the source + * type, otherwise they can be converted to unsigned int. + * 4.5-2 wchar_t or an enumeration can be converted to the first of the + * following that can hold it: int, unsigned int, long unsigned long. + * 4.5-4 bool can be promoted to int + * 4.6 float can be promoted to double + * @throws DOMException + */ + private static final void promotion( Cost cost ) throws DOMException{ + IType src = cost.source; + IType trg = cost.target; - if( ! isCompleteType( source ) ){ - cost.rank = Cost.NO_MATCH_RANK; - return cost; - } + if( src.isSameType( trg ) ) + return; - if( source instanceof ICPPReferenceType ){ - source = ((ICPPReferenceType) source).getType(); - } - if( target instanceof ICPPReferenceType ){ - target = ((ICPPReferenceType) target).getType(); - cost.targetHadReference = true; - } - - //4.3 function to pointer conversion - if( target instanceof IPointerType && ((IPointerType)target).getType() instanceof IFunctionType && - source instanceof IFunctionType ) - { - source = new CPPPointerType( source ); - } - //4.2 Array-To-Pointer conversion - else if( target instanceof IPointerType && source instanceof IArrayType ){ - source = new CPPPointerType( ((IArrayType)source).getType() ); - } - - //4.1 if T is a non-class type, the type of the rvalue is the cv-unqualified version of T - if( source instanceof IQualifierType ){ - IType t = ((IQualifierType)source).getType(); - while( t instanceof ITypedef ) - t = ((ITypedef)t).getType(); - if( !(t instanceof ICPPClassType) ){ - source = t; + if( src instanceof IBasicType && trg instanceof IBasicType ){ + int sType = ((IBasicType)src).getType(); + int tType = ((IBasicType)trg).getType(); + if( ( tType == IBasicType.t_int && ( sType == IBasicType.t_int || //short, long , unsigned etc + sType == IBasicType.t_char || + sType == ICPPBasicType.t_bool || + sType == ICPPBasicType.t_wchar_t || + sType == IBasicType.t_unspecified ) ) || //treat unspecified as int + ( tType == IBasicType.t_double && sType == IBasicType.t_float ) ) + { + cost.promotion = 1; } - } else if( source instanceof IPointerType && - ( ((IPointerType)source).isConst() || ((IPointerType)source).isVolatile() ) ) + } else if( src instanceof IEnumeration && trg instanceof IBasicType && + ( ((IBasicType)trg).getType() == IBasicType.t_int || + ((IBasicType)trg).getType() == IBasicType.t_unspecified ) ) { - IType t = ((IPointerType)source).getType(); - while( t instanceof ITypedef ) - t = ((ITypedef)t).getType(); - if( !(t instanceof ICPPClassType) ){ - source = new CPPPointerType( t ); - } + cost.promotion = 1; } - cost.source = source; - cost.target = target; - - return cost; + cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK; } + + /** + * [4.7] Integral conversions + * [4.8] Floating point conversions + * [4.9] Floating-integral conversions + * [4.10] Pointer conversions + * [4.11] Pointer to member conversions + * @param cost + * @throws DOMException + */ + private static final void conversion( Cost cost ) throws DOMException{ + final IType src = cost.source; + final IType trg = cost.target; - static private boolean isCompleteType( IType type ){ - type = getUltimateType( type, false ); - if( type instanceof ICPPClassType && type instanceof ICPPInternalBinding ) - return (((ICPPInternalBinding)type).getDefinition() != null ); + cost.conversion = 0; + cost.detail = 0; + + IType[] sHolder= new IType[1], tHolder= new IType[1]; + IType s = getUltimateType( src, sHolder, true ); + IType t = getUltimateType( trg, tHolder, true ); + IType sPrev= sHolder[0], tPrev= tHolder[0]; + + if( src instanceof IBasicType && trg instanceof IPointerType ){ + //4.10-1 an integral constant expression of integer type that evaluates to 0 can be converted to a pointer type + IASTExpression exp = ((IBasicType)src).getValue(); + if( exp instanceof IASTLiteralExpression && + ((IASTLiteralExpression)exp).getKind() == IASTLiteralExpression.lk_integer_constant ) + { + try { + String val = exp.toString().toLowerCase().replace('u', '0'); + val.replace( 'l', '0' ); + if( Integer.decode( val ).intValue() == 0 ){ + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + } + } catch( NumberFormatException e ) { + } + } + } else if( sPrev instanceof IPointerType ){ + //4.10-2 an rvalue of type "pointer to cv T", where T is an object type can be + //converted to an rvalue of type "pointer to cv void" + if( tPrev instanceof IPointerType && t instanceof IBasicType && ((IBasicType)t).getType() == IBasicType.t_void ){ + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + cost.detail = 2; + return; + } + //4.10-3 An rvalue of type "pointer to cv D", where D is a class type can be converted + //to an rvalue of type "pointer to cv B", where B is a base class of D. + else if( s instanceof ICPPClassType && tPrev instanceof IPointerType && t instanceof ICPPClassType ){ + int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, (ICPPClassType)s, (ICPPClassType) t ); + cost.rank= ( depth > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; + cost.conversion= ( depth > -1 ) ? depth : 0; + cost.detail= 1; + return; + } + // 4.12 if the target is a bool, we can still convert + else if(!(trg instanceof IBasicType && ((IBasicType)trg).getType() == ICPPBasicType.t_bool)) { + return; + } + } + + if( t instanceof IBasicType && s instanceof IBasicType || s instanceof IEnumeration ){ + //4.7 An rvalue of an integer type can be converted to an rvalue of another integer type. + //An rvalue of an enumeration type can be converted to an rvalue of an integer type. + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + } else if( trg instanceof IBasicType && ((IBasicType)trg).getType() == ICPPBasicType.t_bool && s instanceof IPointerType ){ + //4.12 pointer or pointer to member type can be converted to an rvalue of type bool + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + } else if( s instanceof ICPPPointerToMemberType && t instanceof ICPPPointerToMemberType ){ + //4.11-2 An rvalue of type "pointer to member of B of type cv T", where B is a class type, + //can be converted to an rvalue of type "pointer to member of D of type cv T" where D is a + //derived class of B + ICPPPointerToMemberType spm = (ICPPPointerToMemberType) s; + ICPPPointerToMemberType tpm = (ICPPPointerToMemberType) t; + IType st = spm.getType(); + IType tt = tpm.getType(); + if( st != null && tt != null && st.isSameType( tt ) ){ + int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, tpm.getMemberOfClass(), spm.getMemberOfClass()); + cost.rank= ( depth > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; + cost.conversion= ( depth > -1 ) ? depth : 0; + cost.detail= 1; + } + } + } + + /** + * [13.3.3.1-6] Derived to base conversion + * @param cost + * @throws DOMException + */ + private static final void derivedToBaseConversion(Cost cost) throws DOMException { + IType s = getUltimateType(cost.source, true); + IType t = getUltimateType(cost.target, true); + + if (cost.targetHadReference && s instanceof ICPPClassType && t instanceof ICPPClassType) { + int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, (ICPPClassType) s, (ICPPClassType) t); + if (depth > -1) { + cost.rank = Cost.DERIVED_TO_BASE_CONVERSION; + cost.conversion = depth; + } + } + } + + /** + * @param type + * @return whether the specified type has an associated definition + */ + private static final boolean isCompleteType(IType type) { + type= getUltimateType(type, false); + if(type instanceof ICPPClassType) { + if(type instanceof ICPPInternalBinding) { + return (((ICPPInternalBinding)type).getDefinition() != null ); + } + if(type instanceof IIndexFragmentBinding) { + try { + return ((IIndexFragmentBinding)type).hasDefinition(); + } catch(CoreException ce) { + CCorePlugin.log(ce); + } + } + } + return true; } - static private void relaxTemplateParameters( Cost cost ){ + /** + * Allows any very loose matching between template parameters. + * @param cost + */ + private static final void relaxTemplateParameters( Cost cost ){ IType s = getUltimateType( cost.source, false ); IType t = getUltimateType( cost.target, false );