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
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 );