mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-28 11:25:35 +02:00
222418: apply fix
This commit is contained in:
parent
2942d637ad
commit
e4f737f6b1
5 changed files with 576 additions and 241 deletions
|
@ -4243,7 +4243,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
// f4(vi);
|
// f4(vi);
|
||||||
// f4(cvi);
|
// f4(cvi);
|
||||||
// }
|
// }
|
||||||
public void _testBug222418_a() throws Exception {
|
public void testBug222418_a() throws Exception {
|
||||||
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
ba.assertNonProblem("f1(i)",2);
|
ba.assertNonProblem("f1(i)",2);
|
||||||
ba.assertProblem("f1(ci)", 2);
|
ba.assertProblem("f1(ci)", 2);
|
||||||
|
@ -4282,7 +4282,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
// f1(vi); // (3)
|
// f1(vi); // (3)
|
||||||
// f1(cvi); // (4)
|
// f1(cvi); // (4)
|
||||||
// }
|
// }
|
||||||
public void _testBug222418_b() throws Exception {
|
public void testBug222418_b() throws Exception {
|
||||||
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
|
|
||||||
ICPPFunction f1_1= ba.assertNonProblem("f1(i)", 2, ICPPFunction.class);
|
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
|
// fc(five()); // should be an error
|
||||||
// fd(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);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
|
|
||||||
ICPPFunction fn= ba.assertNonProblem("five() {", 4, ICPPFunction.class);
|
ICPPFunction fn= ba.assertNonProblem("five() {", 4, ICPPFunction.class);
|
||||||
|
@ -4358,7 +4358,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
// f_const(2); // ok
|
// f_const(2); // ok
|
||||||
// f_nonconst(2); // should be an error
|
// 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);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
ba.assertNonProblem("f_const(2", 7, ICPPFunction.class);
|
ba.assertNonProblem("f_const(2", 7, ICPPFunction.class);
|
||||||
ba.assertProblem("f_nonconst(2", 10);
|
ba.assertProblem("f_nonconst(2", 10);
|
||||||
|
@ -4397,7 +4397,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
// f4(vi);
|
// f4(vi);
|
||||||
// f4(cvi);
|
// f4(cvi);
|
||||||
// }
|
// }
|
||||||
public void _testBug222418_e() throws Exception {
|
public void testBug222418_e() throws Exception {
|
||||||
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
ba.assertNonProblem("f1(i)",2);
|
ba.assertNonProblem("f1(i)",2);
|
||||||
ba.assertProblem("f1(ci)", 2);
|
ba.assertProblem("f1(ci)", 2);
|
||||||
|
@ -4472,7 +4472,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
//
|
//
|
||||||
// return 0;
|
// return 0;
|
||||||
// }
|
// }
|
||||||
public void _testBug222418_f() throws Exception {
|
public void testBug222418_f() throws Exception {
|
||||||
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
ba.assertNonProblem("foo1(a)", 4);
|
ba.assertNonProblem("foo1(a)", 4);
|
||||||
ba.assertNonProblem("foo2(a)", 4);
|
ba.assertNonProblem("foo2(a)", 4);
|
||||||
|
@ -4561,7 +4561,7 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
//
|
//
|
||||||
// return ri;
|
// return ri;
|
||||||
// }
|
// }
|
||||||
public void _testBug222418_j() throws Exception {
|
public void testBug222418_j() throws Exception {
|
||||||
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
|
||||||
|
|
||||||
ba.assertNonProblem("fi(ri)", 2);
|
ba.assertNonProblem("fi(ri)", 2);
|
||||||
|
@ -4591,6 +4591,20 @@ public class AST2Tests extends AST2BaseTest {
|
||||||
ba.assertProblem("fcpr(rwp)", 4);
|
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 B {};
|
||||||
//
|
//
|
||||||
// class C {
|
// class C {
|
||||||
|
|
|
@ -328,8 +328,8 @@ public class IndexNamesTests extends BaseTestCase {
|
||||||
final String name = indexName.toString();
|
final String name = indexName.toString();
|
||||||
final char c0= name.length() > 0 ? name.charAt(0) : 0;
|
final char c0= name.length() > 0 ? name.charAt(0) : 0;
|
||||||
if ((c0 == '_' || c0 == 'r' || c0 == 'w') && indexName.isReference()) {
|
if ((c0 == '_' || c0 == 'r' || c0 == 'w') && indexName.isReference()) {
|
||||||
boolean isRead= name.charAt(0) == 'r';
|
boolean isRead= name.charAt(0) == 'r' || name.charAt(0) == 'u';
|
||||||
boolean isWrite= name.charAt(isRead ? 1 : 0) == 'w';
|
boolean isWrite= name.charAt(isRead ? 1 : 0) == 'w' || name.charAt(0) == 'u';
|
||||||
String msg= "i=" + i + ", " + name + ":";
|
String msg= "i=" + i + ", " + name + ":";
|
||||||
assertEquals(msg, isRead, indexName.isReadAccess());
|
assertEquals(msg, isRead, indexName.isReadAccess());
|
||||||
assertEquals(msg, isWrite, indexName.isWriteAccess());
|
assertEquals(msg, isWrite, indexName.isWriteAccess());
|
||||||
|
@ -346,8 +346,8 @@ public class IndexNamesTests extends BaseTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// int _i, ri, wi, rwi, rfind, ridebug;
|
// int _i, ri, wi, rwi, rfind, ui;
|
||||||
// int* rp; int* wp; int* rwp;
|
// int* rp; int* wp; int* rwp; int* up;
|
||||||
// int* const rpc= 0;
|
// int* const rpc= 0;
|
||||||
// const int * const rcpc= 0;
|
// const int * const rcpc= 0;
|
||||||
// const int* cip= &ri;
|
// const int* cip= &ri;
|
||||||
|
@ -366,7 +366,7 @@ public class IndexNamesTests extends BaseTestCase {
|
||||||
// void fcpcp(int const *const*);
|
// void fcpcp(int const *const*);
|
||||||
// void fcpcr(int const *const&);
|
// void fcpcr(int const *const&);
|
||||||
//
|
//
|
||||||
// void test() {
|
// int test() {
|
||||||
// _i;
|
// _i;
|
||||||
// wi= ri, _i, _i; // expr-list
|
// wi= ri, _i, _i; // expr-list
|
||||||
// rwi %= ri; // assignment
|
// rwi %= ri; // assignment
|
||||||
|
@ -378,10 +378,10 @@ public class IndexNamesTests extends BaseTestCase {
|
||||||
// while(ri) {_i;};
|
// while(ri) {_i;};
|
||||||
// switch(ri) {case ri: _i;};
|
// switch(ri) {case ri: _i;};
|
||||||
// fi(ri); fp(&rwi); fcp(&ri);
|
// fi(ri); fp(&rwi); fcp(&ri);
|
||||||
// fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&rwp); fpcp(&rpc); fcpcp(&rcpc);
|
// fi(*rp); fp(rp); fcp(rp); fpp(&rwp); fcpp(&up); fpcp(&rpc); fcpcp(&rcpc);
|
||||||
// fr(rwi); fcr(ri); fpr(&rwi);
|
// fr(rwi); fcr(ri); fpr(&ui);
|
||||||
// fcpr(&ridebug); fpcr(&rwi); fcpcr(&ri);
|
// fcpr(&ui); fpcr(&rwi); fcpcr(&ri);
|
||||||
// fpr(rwp); fcpr(rwp); fpcr(rp); fcpcr(rp);
|
// fpr(rwp); fcpr(up); fpcr(rp); fcpcr(rp);
|
||||||
// return ri;
|
// return ri;
|
||||||
// }
|
// }
|
||||||
public void testReadWriteFlagsCpp() throws Exception {
|
public void testReadWriteFlagsCpp() throws Exception {
|
||||||
|
@ -390,6 +390,6 @@ public class IndexNamesTests extends BaseTestCase {
|
||||||
IFile file= createFile(getProject().getProject(), "test.cpp", content);
|
IFile file= createFile(getProject().getProject(), "test.cpp", content);
|
||||||
waitUntilFileIsIndexed(file, 4000);
|
waitUntilFileIsIndexed(file, 4000);
|
||||||
|
|
||||||
checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 51);
|
checkReadWriteFlags(file, ILinkage.CPP_LINKAGE_ID, 47);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ public class CPPSemantics {
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
static private LookupData createLookupData( IASTName name, boolean considerAssociatedScopes ){
|
private static LookupData createLookupData( IASTName name, boolean considerAssociatedScopes ){
|
||||||
LookupData data = new LookupData( name );
|
LookupData data = new LookupData( name );
|
||||||
IASTNode parent = name.getParent();
|
IASTNode parent = name.getParent();
|
||||||
|
|
||||||
|
@ -1895,6 +1895,7 @@ public class CPPSemantics {
|
||||||
Cost [] bestFnCost = null; //the cost of the best function
|
Cost [] bestFnCost = null; //the cost of the best function
|
||||||
Cost [] currFnCost = null; //the cost for the current function
|
Cost [] currFnCost = null; //the cost for the current function
|
||||||
|
|
||||||
|
IASTExpression sourceExp;
|
||||||
IType source = null; //parameter we are called with
|
IType source = null; //parameter we are called with
|
||||||
IType target = null; //function's parameter
|
IType target = null; //function's parameter
|
||||||
|
|
||||||
|
@ -1934,8 +1935,12 @@ public class CPPSemantics {
|
||||||
if (useImplicitObj > 0) {
|
if (useImplicitObj > 0) {
|
||||||
isImpliedObject= j==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 {
|
} else {
|
||||||
source = sourceParameters[j];
|
source = sourceParameters[j];
|
||||||
|
Object se= data.functionParameters.length==0 ? null : data.functionParameters[j];
|
||||||
|
sourceExp= se instanceof IASTExpression ? (IASTExpression) se : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j < numTargetParams) {
|
if (j < numTargetParams) {
|
||||||
|
@ -1960,16 +1965,7 @@ public class CPPSemantics {
|
||||||
cost = new Cost( source, target );
|
cost = new Cost( source, target );
|
||||||
cost.rank = Cost.IDENTITY_RANK; //exact match, no cost
|
cost.rank = Cost.IDENTITY_RANK; //exact match, no cost
|
||||||
} else {
|
} else {
|
||||||
cost = Conversions.checkStandardConversionSequence( source, target, isImpliedObject);
|
cost= Conversions.checkImplicitConversionSequence(!data.forUserDefinedConversion, sourceExp, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currFnCost[ j ] = cost;
|
currFnCost[ j ] = cost;
|
||||||
|
|
|
@ -2183,4 +2183,37 @@ public class CPPVisitor {
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.getUltimateType;
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeViaTypedefs;
|
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.DOMException;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
|
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.CPPClassType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
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.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
|
* Routines for calculating the cost of conversions.
|
||||||
*
|
|
||||||
* See
|
|
||||||
* [conv] 4
|
|
||||||
* [over.best.ics] 13.3.3.1.
|
|
||||||
*/
|
*/
|
||||||
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 <ul>
|
||||||
|
* <li>GT 1 if cv1 is more qualified than cv2
|
||||||
|
* <li>EQ 0 if cv1 and cv2 are equally qualified
|
||||||
|
* <li>LT -1 if cv1 is less qualified than cv2
|
||||||
|
* <li>NC null if cv1 and cv2 are not comparable
|
||||||
|
* </ul>
|
||||||
|
* @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 <code>cv1t1</code> is reference-related to <code>cv2t2</code>
|
||||||
|
* @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 <code>cv1t1</code> is reference-compatible with <code>cv2t2</code>
|
||||||
|
* @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.
|
* Computes the cost of using the standard conversion sequence from source to target.
|
||||||
* @param isImplicitThis handles the special case when members of different
|
* @param isImplicitThis handles the special case when members of different
|
||||||
* classes are nominated via using-declarations. In such a situation the derived to
|
* classes are nominated via using-declarations. In such a situation the derived to
|
||||||
* base conversion does not cause any costs.
|
* base conversion does not cause any costs.
|
||||||
* @throws DOMException
|
* @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 );
|
Cost cost = lvalue_to_rvalue( source, target );
|
||||||
|
|
||||||
if( cost.source == null || cost.target == null ){
|
if( cost.source == null || cost.target == null ){
|
||||||
|
@ -119,7 +355,14 @@ class Conversions {
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Cost checkUserDefinedConversionSequence( IType source, IType target ) throws DOMException {
|
/**
|
||||||
|
* [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 constructorCost= null;
|
||||||
Cost operatorCost= null;
|
Cost operatorCost= null;
|
||||||
|
|
||||||
|
@ -129,7 +372,6 @@ class Conversions {
|
||||||
//constructors
|
//constructors
|
||||||
if (t instanceof ICPPClassType) {
|
if (t instanceof ICPPClassType) {
|
||||||
ICPPConstructor [] constructors= ((ICPPClassType)t).getConstructors();
|
ICPPConstructor [] constructors= ((ICPPClassType)t).getConstructors();
|
||||||
if( constructors.length > 0 ){
|
|
||||||
if (constructors.length > 0 && constructors[0] instanceof IProblemBinding == false) {
|
if (constructors.length > 0 && constructors[0] instanceof IProblemBinding == false) {
|
||||||
LookupData data= new LookupData();
|
LookupData data= new LookupData();
|
||||||
data.forUserDefinedConversion= true;
|
data.forUserDefinedConversion= true;
|
||||||
|
@ -146,7 +388,6 @@ class Conversions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
boolean checkConversionOperators=
|
boolean checkConversionOperators=
|
||||||
(SemanticUtil.ENABLE_224364 && s instanceof ICPPClassType)
|
(SemanticUtil.ENABLE_224364 && s instanceof ICPPClassType)
|
||||||
|
@ -156,7 +397,7 @@ class Conversions {
|
||||||
|| s instanceof CPPClassInstance);
|
|| s instanceof CPPClassInstance);
|
||||||
|
|
||||||
//conversion operators
|
//conversion operators
|
||||||
boolean ambigousConversionOperator= false;
|
boolean ambiguousConversionOperator= false;
|
||||||
if (checkConversionOperators) {
|
if (checkConversionOperators) {
|
||||||
ICPPMethod [] ops = SemanticUtil.getConversionOperators((ICPPClassType)s);
|
ICPPMethod [] ops = SemanticUtil.getConversionOperators((ICPPClassType)s);
|
||||||
if (ops.length > 0 && ops[0] instanceof IProblemBinding == false) {
|
if (ops.length > 0 && ops[0] instanceof IProblemBinding == false) {
|
||||||
|
@ -169,7 +410,7 @@ class Conversions {
|
||||||
else {
|
else {
|
||||||
int cmp= operatorCost.compare(cost);
|
int cmp= operatorCost.compare(cost);
|
||||||
if (cmp >= 0) {
|
if (cmp >= 0) {
|
||||||
ambigousConversionOperator= cmp == 0;
|
ambiguousConversionOperator= cmp == 0;
|
||||||
operatorCost= cost;
|
operatorCost= cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +420,7 @@ class Conversions {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constructorCost != null) {
|
if (constructorCost != null) {
|
||||||
if (operatorCost == null || ambigousConversionOperator) {
|
if (operatorCost == null || ambiguousConversionOperator) {
|
||||||
constructorCost.userDefined = Cost.USERDEFINED_CONVERSION;
|
constructorCost.userDefined = Cost.USERDEFINED_CONVERSION;
|
||||||
constructorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
|
constructorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +433,7 @@ class Conversions {
|
||||||
}
|
}
|
||||||
if (operatorCost != null) {
|
if (operatorCost != null) {
|
||||||
operatorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
|
operatorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
|
||||||
if (ambigousConversionOperator) {
|
if (ambiguousConversionOperator) {
|
||||||
operatorCost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION;
|
operatorCost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -212,9 +453,10 @@ class Conversions {
|
||||||
* no inheritance relation
|
* no inheritance relation
|
||||||
* @throws DOMException
|
* @throws DOMException
|
||||||
*/
|
*/
|
||||||
private static int calculateInheritanceDepth(int maxdepth, ICPPClassType clazz, ICPPClassType ancestorToFind) throws DOMException {
|
private static final int calculateInheritanceDepth(int maxdepth, ICPPClassType clazz, ICPPClassType ancestorToFind) throws DOMException {
|
||||||
if(clazz == ancestorToFind || clazz.isSameType(ancestorToFind))
|
if (clazz == ancestorToFind || clazz.isSameType(ancestorToFind)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (maxdepth>0) {
|
if (maxdepth>0) {
|
||||||
ICPPBase[] bases= clazz.getBases();
|
ICPPBase[] bases= clazz.getBases();
|
||||||
|
@ -242,137 +484,74 @@ class Conversions {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static private void conversion( Cost cost ) throws DOMException{
|
/**
|
||||||
IType src = cost.source;
|
* [4.1] Lvalue-to-rvalue conversion
|
||||||
IType trg = cost.target;
|
* [4.2] array-to-ptr
|
||||||
|
* [4.3] function-to-ptr
|
||||||
|
*
|
||||||
|
* @param source
|
||||||
|
* @param target
|
||||||
|
* @return
|
||||||
|
* @throws DOMException
|
||||||
|
*/
|
||||||
|
private static final Cost lvalue_to_rvalue(IType source, IType target) throws DOMException {
|
||||||
|
Cost cost = new Cost(source, target);
|
||||||
|
|
||||||
cost.conversion = 0;
|
if (!isCompleteType(source)) {
|
||||||
cost.detail = 0;
|
cost.rank= Cost.NO_MATCH_RANK;
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
IType[] sHolder= new IType[1], tHolder= new IType[1];
|
if (source instanceof ICPPReferenceType) {
|
||||||
IType s = getUltimateType( src, sHolder, true );
|
source= ((ICPPReferenceType) source).getType();
|
||||||
IType t = getUltimateType( trg, tHolder, true );
|
}
|
||||||
IType sPrev= sHolder[0], tPrev= tHolder[0];
|
if (target instanceof ICPPReferenceType) {
|
||||||
|
target= ((ICPPReferenceType) target).getType();
|
||||||
|
cost.targetHadReference = true;
|
||||||
|
}
|
||||||
|
|
||||||
if( src instanceof IBasicType && trg instanceof IPointerType ){
|
//4.3 function to pointer conversion
|
||||||
//4.10-1 an integral constant expression of integer type that evaluates to 0 can be converted to a pointer type
|
if( target instanceof IPointerType && ((IPointerType)target).getType() instanceof IFunctionType &&
|
||||||
IASTExpression exp = ((IBasicType)src).getValue();
|
source instanceof IFunctionType )
|
||||||
if( exp instanceof IASTLiteralExpression &&
|
|
||||||
((IASTLiteralExpression)exp).getKind() == IASTLiteralExpression.lk_integer_constant )
|
|
||||||
{
|
{
|
||||||
try {
|
source = new CPPPointerType( source );
|
||||||
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 ) {
|
//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( sPrev instanceof IPointerType ){
|
} else if( source instanceof IPointerType &&
|
||||||
//4.10-2 an rvalue of type "pointer to cv T", where T is an object type can be
|
( ((IPointerType)source).isConst() || ((IPointerType)source).isVolatile() ) )
|
||||||
//converted to an rvalue of type "pointer to cv void"
|
{
|
||||||
if( tPrev instanceof IPointerType && t instanceof IBasicType && ((IBasicType)t).getType() == IBasicType.t_void ){
|
IType t= ((IPointerType) source).getType();
|
||||||
cost.rank = Cost.CONVERSION_RANK;
|
while (t instanceof ITypedef)
|
||||||
cost.conversion = 1;
|
t= ((ITypedef) t).getType();
|
||||||
cost.detail = 2;
|
if (!(t instanceof ICPPClassType)) {
|
||||||
return;
|
source= new CPPPointerType(t);
|
||||||
}
|
|
||||||
//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 ){
|
cost.source = source;
|
||||||
//4.7 An rvalue of an integer type can be converted to an rvalue of another integer type.
|
cost.target = target;
|
||||||
//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 {
|
return cost;
|
||||||
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
|
* [4.4] Qualifications
|
||||||
* can be converted to int if int can represent all the values of the source
|
* @param cost
|
||||||
* 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
|
* @throws DOMException
|
||||||
*/
|
*/
|
||||||
static private void promotion( Cost cost ) throws DOMException{
|
private static final void qualificationConversion( Cost cost ) throws DOMException{
|
||||||
IType src = cost.source;
|
|
||||||
IType trg = cost.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private void qualificationConversion( Cost cost ) throws DOMException{
|
|
||||||
boolean canConvert = true;
|
boolean canConvert = true;
|
||||||
int requiredConversion = Cost.IDENTITY_RANK;
|
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 ) ){
|
if( src.isSameType( trg ) )
|
||||||
cost.rank = Cost.NO_MATCH_RANK;
|
return;
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( source instanceof ICPPReferenceType ){
|
if( src instanceof IBasicType && trg instanceof IBasicType ){
|
||||||
source = ((ICPPReferenceType) source).getType();
|
int sType = ((IBasicType)src).getType();
|
||||||
}
|
int tType = ((IBasicType)trg).getType();
|
||||||
if( target instanceof ICPPReferenceType ){
|
if( ( tType == IBasicType.t_int && ( sType == IBasicType.t_int || //short, long , unsigned etc
|
||||||
target = ((ICPPReferenceType) target).getType();
|
sType == IBasicType.t_char ||
|
||||||
cost.targetHadReference = true;
|
sType == ICPPBasicType.t_bool ||
|
||||||
}
|
sType == ICPPBasicType.t_wchar_t ||
|
||||||
|
sType == IBasicType.t_unspecified ) ) || //treat unspecified as int
|
||||||
//4.3 function to pointer conversion
|
( tType == IBasicType.t_double && sType == IBasicType.t_float ) )
|
||||||
if( target instanceof IPointerType && ((IPointerType)target).getType() instanceof IFunctionType &&
|
|
||||||
source instanceof IFunctionType )
|
|
||||||
{
|
{
|
||||||
source = new CPPPointerType( source );
|
cost.promotion = 1;
|
||||||
}
|
}
|
||||||
//4.2 Array-To-Pointer conversion
|
} else if( src instanceof IEnumeration && trg instanceof IBasicType &&
|
||||||
else if( target instanceof IPointerType && source instanceof IArrayType ){
|
( ((IBasicType)trg).getType() == IBasicType.t_int ||
|
||||||
source = new CPPPointerType( ((IArrayType)source).getType() );
|
((IBasicType)trg).getType() == IBasicType.t_unspecified ) )
|
||||||
}
|
|
||||||
|
|
||||||
//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();
|
cost.promotion = 1;
|
||||||
while( t instanceof ITypedef )
|
}
|
||||||
t = ((ITypedef)t).getType();
|
|
||||||
if( !(t instanceof ICPPClassType) ){
|
cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK;
|
||||||
source = new CPPPointerType( t );
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cost.source = source;
|
if( t instanceof IBasicType && s instanceof IBasicType || s instanceof IEnumeration ){
|
||||||
cost.target = target;
|
//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.
|
||||||
return cost;
|
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 boolean isCompleteType( IType type ){
|
/**
|
||||||
|
* [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);
|
type= getUltimateType(type, false);
|
||||||
if( type instanceof ICPPClassType && type instanceof ICPPInternalBinding )
|
if(type instanceof ICPPClassType) {
|
||||||
|
if(type instanceof ICPPInternalBinding) {
|
||||||
return (((ICPPInternalBinding)type).getDefinition() != null );
|
return (((ICPPInternalBinding)type).getDefinition() != null );
|
||||||
|
}
|
||||||
|
if(type instanceof IIndexFragmentBinding) {
|
||||||
|
try {
|
||||||
|
return ((IIndexFragmentBinding)type).hasDefinition();
|
||||||
|
} catch(CoreException ce) {
|
||||||
|
CCorePlugin.log(ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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 s = getUltimateType( cost.source, false );
|
||||||
IType t = getUltimateType( cost.target, false );
|
IType t = getUltimateType( cost.target, false );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue