1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 380498 - typedef is expanded during refactoring

This commit is contained in:
Sergey Prigogin 2012-05-30 18:25:21 -07:00
parent 3604f812ce
commit 2776e06605
11 changed files with 288 additions and 92 deletions

View file

@ -10,6 +10,7 @@
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian) * Andrew Ferguson (Symbian)
* Mike Kucera (IBM) * Mike Kucera (IBM)
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2; package org.eclipse.cdt.core.parser.tests.ast2;
@ -628,6 +629,23 @@ public class AST2BaseTest extends BaseTestCase {
return selector.findImplicitName(offset, len); return selector.findImplicitName(offset, len);
} }
public <T extends IASTNode> T assertNode(String context, String nodeText, Class<T> type, Class... cs) {
if (context == null) {
context = contents;
}
int offset = contents.indexOf(context);
assertTrue("Context \"" + context + "\" not found", offset >= 0);
int nodeOffset = context.indexOf(nodeText);
assertTrue("Node \"" + nodeText + "\" not found", nodeOffset >= 0);
IASTNodeSelector selector = tu.getNodeSelector(null);
IASTNode node = selector.findNode(offset + nodeOffset, nodeText.length());
return assertType(node, type, cs);
}
public <T extends IASTNode> T assertNode(String nodeText, Class<T> type, Class... cs) {
return assertNode(contents, nodeText, type, cs);
}
private String renderProblemID(int i) { private String renderProblemID(int i) {
try { try {
for (Field field : IProblemBinding.class.getDeclaredFields()) { for (Field field : IProblemBinding.class.getDeclaredFields()) {
@ -652,17 +670,31 @@ public class AST2BaseTest extends BaseTestCase {
IBinding binding= binding(section, len); IBinding binding= binding(section, len);
assertTrue("ProblemBinding for name: " + section.substring(0, len), assertTrue("ProblemBinding for name: " + section.substring(0, len),
!(binding instanceof IProblemBinding)); !(binding instanceof IProblemBinding));
assertInstance(binding, type); return assertType(binding, type, cs);
for (Class c : cs) {
assertInstance(binding, c);
}
return type.cast(binding);
} }
public <T extends IBinding> T assertNonProblem(String section, Class<T> type, Class... cs) {
return assertNonProblem(section, section.length(), type, cs);
}
public <T extends IBinding> T assertNonProblem(String context, String name, Class<T> type, Class... cs) {
IBinding binding= binding(context, name);
assertTrue("ProblemBinding for name: " + name, !(binding instanceof IProblemBinding));
return assertType(binding, type, cs);
}
public <T, U extends T> U assertType(T obj, Class<U> type, Class... cs) {
assertInstance(obj, type);
for (Class c : cs) {
assertInstance(obj, c);
}
return type.cast(obj);
}
private IBinding binding(String section, int len) { private IBinding binding(String section, int len) {
IASTName name = findName(section, len); IASTName name = findName(section, len);
final String selection = section.substring(0, len); final String selection = section.substring(0, len);
assertNotNull("did not find \"" + selection + "\"", name); assertNotNull("Did not find \"" + selection + "\"", name);
assertEquals(selection, name.getRawSignature()); assertEquals(selection, name.getRawSignature());
IBinding binding = name.resolveBinding(); IBinding binding = name.resolveBinding();
@ -670,7 +702,17 @@ public class AST2BaseTest extends BaseTestCase {
return name.resolveBinding(); return name.resolveBinding();
} }
}
private IBinding binding(String context, String name) {
IASTName astName = findName(context, name);
assertEquals(name, astName.getRawSignature());
IBinding binding = astName.resolveBinding();
assertNotNull("No binding for " + astName.getRawSignature(), binding);
return astName.resolveBinding();
}
}
final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang) throws Exception { final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang) throws Exception {
return parseAndCheckBindings(code, lang, false); return parseAndCheckBindings(code, lang, false);

View file

@ -4705,6 +4705,33 @@ public class AST2CPPTests extends AST2BaseTest {
assertSame(i, col.getName(7).resolveBinding()); assertSame(i, col.getName(7).resolveBinding());
} }
// template<typename T>
// class basic_string {
// basic_string& operator+=(const T* s);
// };
//
// template<typename T>
// basic_string<T> operator+(const T* cs, const basic_string<T>& s);
//
// template<typename T>
// basic_string<T> operator+(const basic_string<T>& s, const T* cs);
//
// typedef basic_string<char> string;
//
// void test(const string& s) {
// auto s1 = "" + s + "";
// auto s2 = s1 += "";
// }
public void testTypedefPreservation_380498() throws Exception {
BindingAssertionHelper ba= getAssertionHelper();
ICPPVariable s1 = ba.assertNonProblem("s1", ICPPVariable.class);
assertTrue(s1.getType() instanceof ITypedef);
assertEquals("string", ((ITypedef) s1.getType()).getName());
ICPPVariable s2 = ba.assertNonProblem("s2", ICPPVariable.class);
assertTrue(s2.getType() instanceof ITypedef);
assertEquals("string", ((ITypedef) s2.getType()).getName());
}
// int f() { // int f() {
// return 5; // return 5;
// } // }

View file

@ -9,6 +9,7 @@
* Doug Schaefer (IBM) - Initial API and implementation * Doug Schaefer (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian) * Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2; package org.eclipse.cdt.core.parser.tests.ast2;
@ -6081,6 +6082,29 @@ public class AST2Tests extends AST2BaseTest {
} }
} }
// typedef long unsigned int size_t;
//
// size_t a = 0;
// size_t x = a + 5;
// size_t y = 2 + a;
// size_t y = a * 2;
public void testTypeOfExpressionWithTypedef_380498() throws Exception {
final boolean[] isCpps= { false, true };
String code= getAboveComment();
for (boolean isCpp : isCpps) {
BindingAssertionHelper ba= new BindingAssertionHelper(code, isCpp);
IASTExpression exp = ba.assertNode("a + 5", IASTExpression.class);
assertTrue(exp.getExpressionType() instanceof ITypedef);
assertEquals("size_t", ((ITypedef) exp.getExpressionType()).getName());
exp = ba.assertNode("2 + a", IASTExpression.class);
assertTrue(exp.getExpressionType() instanceof ITypedef);
assertEquals("size_t", ((ITypedef) exp.getExpressionType()).getName());
exp = ba.assertNode("a * 2", IASTExpression.class);
assertTrue(exp.getExpressionType() instanceof ITypedef);
assertEquals("size_t", ((ITypedef) exp.getExpressionType()).getName());
}
}
// typedef int TInt; // typedef int TInt;
// int a= TInt; //ref // int a= TInt; //ref
public void testTypeAsExpressionIsProblem_261175() throws Exception { public void testTypeAsExpressionIsProblem_261175() throws Exception {

View file

@ -9,9 +9,12 @@
* John Camelon (IBM Rational Software) - Initial API and implementation * John Camelon (IBM Rational Software) - Initial API and implementation
* Yuan Zhang / Beth Tibbitts (IBM Research) * Yuan Zhang / Beth Tibbitts (IBM Research)
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c; package org.eclipse.cdt.internal.core.dom.parser.c;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.restoreTypedefs;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
@ -207,11 +210,13 @@ public class CASTBinaryExpression extends ASTNode
@Override @Override
public IType getExpressionType() { public IType getExpressionType() {
final int op = getOperator(); final int op = getOperator();
final IType t1= CVisitor.unwrapTypedefs(getOperand1().getExpressionType()); IType originalType1 = getOperand1().getExpressionType();
final IType t2= CVisitor.unwrapTypedefs(getOperand2().getExpressionType()); IType originalType2 = getOperand2().getExpressionType();
IType type= CArithmeticConversion.convertCOperandTypes(op, t1, t2); final IType type1= CVisitor.unwrapTypedefs(originalType1);
final IType type2= CVisitor.unwrapTypedefs(originalType2);
IType type= CArithmeticConversion.convertCOperandTypes(op, type1, type2);
if (type != null) { if (type != null) {
return type; return restoreTypedefs(type, originalType1, originalType2);
} }
switch (op) { switch (op) {
@ -226,25 +231,25 @@ public class CASTBinaryExpression extends ASTNode
return new CBasicType(Kind.eInt, 0, this); return new CBasicType(Kind.eInt, 0, this);
case IASTBinaryExpression.op_plus: case IASTBinaryExpression.op_plus:
if (t1 instanceof IArrayType) { if (type1 instanceof IArrayType) {
return arrayTypeToPointerType((ICArrayType) t1); return arrayTypeToPointerType((ICArrayType) type1);
} else if (t2 instanceof IPointerType) { } else if (type2 instanceof IPointerType) {
return t2; return restoreTypedefs(type2, originalType2);
} else if (t2 instanceof IArrayType) { } else if (type2 instanceof IArrayType) {
return arrayTypeToPointerType((ICArrayType) t2); return arrayTypeToPointerType((ICArrayType) type2);
} }
break; break;
case IASTBinaryExpression.op_minus: case IASTBinaryExpression.op_minus:
if (t2 instanceof IPointerType || t2 instanceof IArrayType) { if (type2 instanceof IPointerType || type2 instanceof IArrayType) {
if (t1 instanceof IPointerType || t1 instanceof IArrayType) { if (type1 instanceof IPointerType || type1 instanceof IArrayType) {
return CVisitor.getPtrDiffType(this); return CVisitor.getPtrDiffType(this);
} }
return t1; return restoreTypedefs(type1, originalType1);
} }
break; break;
} }
return t1; return restoreTypedefs(type1, originalType1);
} }
private IType arrayTypeToPointerType(ICArrayType type) { private IType arrayTypeToPointerType(ICArrayType type) {

View file

@ -9,9 +9,12 @@
* John Camelon (IBM Rational Software) - Initial API and implementation * John Camelon (IBM Rational Software) - Initial API and implementation
* Yuan Zhang / Beth Tibbitts (IBM Research) * Yuan Zhang / Beth Tibbitts (IBM Research)
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c; package org.eclipse.cdt.internal.core.dom.parser.c;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.restoreTypedefs;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
@ -122,17 +125,17 @@ public class CASTUnaryExpression extends ASTNode implements IASTUnaryExpression,
} }
break; break;
case op_amper: case op_amper:
return new CPointerType(type, 0); return new CPointerType(exprType, 0);
case op_minus: case op_minus:
case op_plus: case op_plus:
case op_tilde: case op_tilde:
IType t= CArithmeticConversion.promoteCType(type); IType t= CArithmeticConversion.promoteCType(type);
if (t != null) { if (t != null) {
return t; return restoreTypedefs(t, exprType);
} }
break; break;
} }
return exprType; // return the original return exprType; // Return the original.
} }
@Override @Override

View file

@ -9,6 +9,7 @@
* John Camelon (IBM) - Initial API and implementation * John Camelon (IBM) - Initial API and implementation
* Mike Kucera (IBM) * Mike Kucera (IBM)
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp; package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -16,6 +17,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.restoreTypedefs;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromFunctionCall; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromFunctionCall;
@ -40,7 +42,6 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent { public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent {
private int op; private int op;
private IASTExpression operand1; private IASTExpression operand1;
@ -313,21 +314,26 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
} }
private IType createExpressionType() { private IType createExpressionType() {
IType originalType1 = operand1.getExpressionType();
IType originalType2 = operand2 instanceof IASTExpression ?
((IASTExpression) operand2).getExpressionType() : null;
// Check for overloaded operator. // Check for overloaded operator.
ICPPFunction o= getOverload(); ICPPFunction o= getOverload();
if (o != null) { if (o != null) {
return typeFromFunctionCall(o); IType type = typeFromFunctionCall(o);
return restoreTypedefs(type, originalType1, originalType2);
} }
final int op = getOperator(); final int op = getOperator();
IType type1 = prvalueType(operand1.getExpressionType()); IType type1 = prvalueType(originalType1);
if (type1 instanceof ISemanticProblem) { if (type1 instanceof ISemanticProblem) {
return type1; return type1;
} }
IType type2 = null; IType type2 = null;
if (operand2 instanceof IASTExpression) { if (originalType2 != null) {
type2= prvalueType(((IASTExpression) operand2).getExpressionType()); type2= prvalueType(originalType2);
if (type2 instanceof ISemanticProblem) { if (type2 instanceof ISemanticProblem) {
return type2; return type2;
} }
@ -335,7 +341,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
IType type= CPPArithmeticConversion.convertCppOperandTypes(op, type1, type2); IType type= CPPArithmeticConversion.convertCppOperandTypes(op, type1, type2);
if (type != null) { if (type != null) {
return type; return restoreTypedefs(type, originalType1, originalType2);
} }
switch (op) { switch (op) {
@ -351,10 +357,10 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
case IASTBinaryExpression.op_plus: case IASTBinaryExpression.op_plus:
if (type1 instanceof IPointerType) { if (type1 instanceof IPointerType) {
return type1; return restoreTypedefs(type1, originalType1);
} }
if (type2 instanceof IPointerType) { if (type2 instanceof IPointerType) {
return type2; return restoreTypedefs(type2, originalType2);
} }
break; break;
@ -363,7 +369,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
if (type2 instanceof IPointerType) { if (type2 instanceof IPointerType) {
return CPPVisitor.getPointerDiffType(this); return CPPVisitor.getPointerDiffType(this);
} }
return type1; return restoreTypedefs(type1, originalType1);
} }
break; break;
@ -380,6 +386,6 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
} }
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
} }
return type1; return restoreTypedefs(type1, originalType1);
} }
} }

View file

@ -72,13 +72,9 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres
@Override @Override
public CPPASTUnaryExpression copy(CopyStyle style) { public CPPASTUnaryExpression copy(CopyStyle style) {
CPPASTUnaryExpression copy = new CPPASTUnaryExpression(op, operand == null ? null CPPASTUnaryExpression copy =
: operand.copy(style)); new CPPASTUnaryExpression(op, operand == null ? null : operand.copy(style));
copy.setOffsetAndLength(this); return copy(copy, style);
if (style == CopyStyle.withLocations) {
copy.setCopyLocation(this);
}
return copy;
} }
@Override @Override

View file

@ -2065,6 +2065,9 @@ public class CPPVisitor extends ASTQueries {
return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE);
} }
type = argument.getTypeValue(); type = argument.getTypeValue();
IType t = SemanticUtil.substituteTypedef(type, initType);
if (t != null)
type = t;
if (initClause instanceof ICPPASTInitializerList) { if (initClause instanceof ICPPASTInitializerList) {
type = (IType) CPPTemplates.instantiate(initializer_list_template, type = (IType) CPPTemplates.instantiate(initializer_list_template,
new ICPPTemplateArgument[] { new CPPTemplateArgument(type) }); new ICPPTemplateArgument[] { new CPPTemplateArgument(type) });

View file

@ -16,7 +16,16 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.COND_TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.addQualifiers;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.calculateInheritanceDepth;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getCVQualifier;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.isVoidType;
import java.util.Collections; import java.util.Collections;
@ -179,7 +188,7 @@ public class Conversions {
return cost; return cost;
} }
} }
// otherwise, the program is ill-formed. // otherwise, the program is ill-formed.
return Cost.NO_CONVERSION; return Cost.NO_CONVERSION;
} }
@ -1147,18 +1156,18 @@ public class Conversions {
* 4.1, 4.2, 4.3 * 4.1, 4.2, 4.3
*/ */
public static IType lvalue_to_rvalue(IType type) { public static IType lvalue_to_rvalue(IType type) {
type= SemanticUtil.getNestedType(type, TDEF | REF); IType t= SemanticUtil.getNestedType(type, TDEF | REF);
if (type instanceof IArrayType) { if (t instanceof IArrayType) {
return new CPPPointerType(((IArrayType) type).getType()); return new CPPPointerType(((IArrayType) t).getType());
} }
if (type instanceof IFunctionType) { if (t instanceof IFunctionType) {
return new CPPPointerType(type); return new CPPPointerType(t);
} }
IType uqType= SemanticUtil.getNestedType(type, TDEF | REF | ALLCVQ); IType uqType= SemanticUtil.getNestedType(t, TDEF | REF | ALLCVQ);
if (uqType instanceof ICPPClassType) { if (uqType instanceof ICPPClassType) {
return type; return SemanticUtil.getNestedType(type, COND_TDEF | REF);
} }
return uqType; return SemanticUtil.getNestedType(t, COND_TDEF | REF | ALLCVQ);
} }
/** /**

View file

@ -7,9 +7,11 @@
* *
* Contributors: * Contributors:
* Markus Schorn - initial API and implementation * Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.COND_TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
@ -27,13 +29,13 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
/** /**
* Methods for computing the type of an expression * Methods for computing the type of an expression.
*/ */
public class ExpressionTypes { public class ExpressionTypes {
public static IType glvalueType(IType type) { public static IType glvalueType(IType type) {
// Reference types are removed. // Reference types are removed.
return SemanticUtil.getNestedType(type, TDEF | REF); return SemanticUtil.getNestedType(type, COND_TDEF | REF);
} }
public static IType prvalueType(IType type) { public static IType prvalueType(IType type) {
@ -65,46 +67,46 @@ public class ExpressionTypes {
return typeFromReturnType(ft.getReturnType()); return typeFromReturnType(ft.getReturnType());
} }
public static IType typeFromReturnType(IType r) { public static IType typeFromReturnType(IType type) {
r= SemanticUtil.getNestedType(r, TDEF); IType t= SemanticUtil.getNestedType(type, TDEF);
if (r instanceof ICPPReferenceType) { if (t instanceof ICPPReferenceType) {
return glvalueType(r); return glvalueType(type);
} }
return prvalueType(r); return prvalueType(type);
} }
public static IType typeOrFunctionSet(IASTExpression e) { public static IType typeOrFunctionSet(IASTExpression exp) {
FunctionSetType fs= getFunctionSetType(e); FunctionSetType fs= getFunctionSetType(exp);
if (fs != null) { if (fs != null) {
return fs; return fs;
} }
return e.getExpressionType(); return exp.getExpressionType();
} }
public static ValueCategory valueCat(IASTExpression e) { public static ValueCategory valueCat(IASTExpression exp) {
FunctionSetType fs= getFunctionSetType(e); FunctionSetType fs= getFunctionSetType(exp);
if (fs != null) if (fs != null)
return fs.getValueCategory(); return fs.getValueCategory();
return e.getValueCategory(); return exp.getValueCategory();
} }
private static FunctionSetType getFunctionSetType(IASTExpression e) { private static FunctionSetType getFunctionSetType(IASTExpression exp) {
boolean addressOf= false; boolean addressOf= false;
while (e instanceof IASTUnaryExpression) { while (exp instanceof IASTUnaryExpression) {
final IASTUnaryExpression unary = (IASTUnaryExpression) e; final IASTUnaryExpression unary = (IASTUnaryExpression) exp;
final int op= unary.getOperator(); final int op= unary.getOperator();
if (op == IASTUnaryExpression.op_bracketedPrimary) { if (op == IASTUnaryExpression.op_bracketedPrimary) {
e= unary.getOperand(); exp= unary.getOperand();
} else if (!addressOf && op == IASTUnaryExpression.op_amper) { } else if (!addressOf && op == IASTUnaryExpression.op_amper) {
addressOf= true; addressOf= true;
e= unary.getOperand(); exp= unary.getOperand();
} else { } else {
break; break;
} }
} }
if (e instanceof IASTIdExpression) { if (exp instanceof IASTIdExpression) {
IASTIdExpression idexpr= (IASTIdExpression) e; IASTIdExpression idexpr= (IASTIdExpression) exp;
final IASTName name = idexpr.getName(); final IASTName name = idexpr.getName();
IBinding b= name.resolvePreBinding(); IBinding b= name.resolvePreBinding();
if (b instanceof CPPFunctionSet) { if (b instanceof CPPFunctionSet) {
@ -113,4 +115,23 @@ public class ExpressionTypes {
} }
return null; return null;
} }
public static IType restoreTypedefs(IType type, IType originalType) {
IType t = SemanticUtil.substituteTypedef(type, originalType);
if (t != null)
return t;
return type;
}
public static IType restoreTypedefs(IType type, IType originalType1, IType originalType2) {
IType t = SemanticUtil.substituteTypedef(type, originalType1);
if (t != null)
return t;
if (originalType2 != null) {
t = SemanticUtil.substituteTypedef(type, originalType2);
if (t != null)
return t;
}
return type;
}
} }

View file

@ -14,7 +14,14 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.*; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.CONST;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.CONST_RESTRICT;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.CONST_VOLATILE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.CONST_VOLATILE_RESTRICT;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.NONE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.RESTRICT;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.VOLATILE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier.VOLATILE_RESTRICT;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -60,20 +67,23 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
/** /**
* * Collection of static methods operating on C++ bindings.
*/ */
public class SemanticUtil { public class SemanticUtil {
private static final char[] OPERATOR_CHARS = Keywords.OPERATOR.toCharArray(); private static final char[] OPERATOR_CHARS = Keywords.OPERATOR.toCharArray();
// Cache of overloadable operator names for fast lookup. Used by isConversionOperator. // Cache of overloadable operator names for fast lookup. Used by isConversionOperator.
private static final CharArraySet cas= new CharArraySet(OverloadableOperator.values().length); private static final CharArraySet cas= new CharArraySet(OverloadableOperator.values().length);
public static final int TDEF = 0x01; // Resolve typedefs.
public static final int REF = 0x02; public static final int TDEF = 0x01;
public static final int CVTYPE = 0x04; // Resolve typedefs, but only if necessary for a nested type transformation.
public static final int ALLCVQ= 0x08; public static final int COND_TDEF = 0x02;
public static final int PTR= 0x10; public static final int REF = 0x04;
public static final int MPTR= 0x20; public static final int CVTYPE = 0x08;
public static final int ARRAY= 0x40; public static final int ALLCVQ = 0x10;
public static final int PTR = 0x20;
public static final int MPTR = 0x40;
public static final int ARRAY = 0x80;
static { static {
final int OPERATOR_SPC= OPERATOR_CHARS.length + 1; final int OPERATOR_SPC= OPERATOR_CHARS.length + 1;
@ -221,14 +231,25 @@ public class SemanticUtil {
*/ */
public static IType getNestedType(IType type, int options) { public static IType getNestedType(IType type, int options) {
final boolean tdef= (options & TDEF) != 0; final boolean tdef= (options & TDEF) != 0;
final boolean cond_tdef= (options & COND_TDEF) != 0;
final boolean ptr= (options & PTR) != 0; final boolean ptr= (options & PTR) != 0;
final boolean mptr= (options & MPTR) != 0; final boolean mptr= (options & MPTR) != 0;
final boolean allcvq= (options & ALLCVQ) != 0; final boolean allcvq= (options & ALLCVQ) != 0;
final boolean cvtype = (options & CVTYPE) != 0; final boolean cvtype = (options & CVTYPE) != 0;
IType beforeTypedefs = null;
while (true) { while (true) {
IType t= null; IType t= null;
if (type instanceof IPointerType) { if (type instanceof ITypedef) {
if (tdef || cond_tdef) {
if (beforeTypedefs == null && cond_tdef) {
beforeTypedefs = type;
}
t= ((ITypedef) type).getType();
}
} else if (type instanceof IPointerType) {
beforeTypedefs = null;
final boolean isMbrPtr = type instanceof ICPPPointerToMemberType; final boolean isMbrPtr = type instanceof ICPPPointerToMemberType;
if ((ptr && !isMbrPtr) || (mptr && isMbrPtr)) { if ((ptr && !isMbrPtr) || (mptr && isMbrPtr)) {
t= ((IPointerType) type).getType(); t= ((IPointerType) type).getType();
@ -244,20 +265,20 @@ public class SemanticUtil {
} }
return pt; return pt;
} }
} else if (tdef && type instanceof ITypedef) {
t= ((ITypedef) type).getType();
} else if (type instanceof IQualifierType) { } else if (type instanceof IQualifierType) {
beforeTypedefs = null;
final IQualifierType qt = (IQualifierType) type; final IQualifierType qt = (IQualifierType) type;
final IType qttgt = qt.getType(); final IType qttgt = qt.getType();
if (allcvq || cvtype) { if (allcvq || cvtype) {
t= qttgt; t= qttgt;
} else if (tdef) { } else if (tdef || cond_tdef) {
t= getNestedType(qttgt, options); t= getNestedType(qttgt, options);
if (t == qttgt) if (t == qttgt)
return qt; return qt;
return addQualifiers(t, qt.isConst(), qt.isVolatile(), false); return addQualifiers(t, qt.isConst(), qt.isVolatile(), false);
} }
} else if (type instanceof IArrayType) { } else if (type instanceof IArrayType) {
beforeTypedefs = null;
final IArrayType atype= (IArrayType) type; final IArrayType atype= (IArrayType) type;
if ((options & ARRAY) != 0) { if ((options & ARRAY) != 0) {
t= atype.getType(); t= atype.getType();
@ -269,11 +290,12 @@ public class SemanticUtil {
return replaceNestedType((ITypeContainer) atype, newNested); return replaceNestedType((ITypeContainer) atype, newNested);
} }
} else if (type instanceof ICPPReferenceType) { } else if (type instanceof ICPPReferenceType) {
beforeTypedefs = null;
final ICPPReferenceType rt = (ICPPReferenceType) type; final ICPPReferenceType rt = (ICPPReferenceType) type;
if ((options & REF) != 0) { if ((options & REF) != 0) {
t= rt.getType(); t= rt.getType();
} else if (tdef) { } else if (tdef) {
// a typedef within the reference type can influence whether the reference is lvalue or rvalue // A typedef within the reference type can influence whether the reference is lvalue or rvalue
IType nested= rt.getType(); IType nested= rt.getType();
IType newNested = getNestedType(nested, TDEF); IType newNested = getNestedType(nested, TDEF);
if (nested == newNested) if (nested == newNested)
@ -282,8 +304,12 @@ public class SemanticUtil {
} }
} }
// Pack expansion types are dependent types, there is no need to descend into those. // Pack expansion types are dependent types, there is no need to descend into those.
if (t == null) if (t == null) {
if (beforeTypedefs != null) {
return beforeTypedefs;
}
return type; return type;
}
type= t; type= t;
} }
@ -354,7 +380,7 @@ public class SemanticUtil {
if (newNestedType == null) if (newNestedType == null)
return type; return type;
// bug 249085 make sure not to add unnecessary qualifications // Bug 249085 make sure not to add unnecessary qualifications
if (type instanceof IQualifierType) { if (type instanceof IQualifierType) {
IQualifierType qt= (IQualifierType) type; IQualifierType qt= (IQualifierType) type;
return addQualifiers(newNestedType, qt.isConst(), qt.isVolatile(), false); return addQualifiers(newNestedType, qt.isConst(), qt.isVolatile(), false);
@ -365,6 +391,40 @@ public class SemanticUtil {
return type; return type;
} }
/**
* Replaces the given type or its nested type with a typedef if that type is the same as
* the type the typedef resolves to.
*
* @param type the type subject to substitution
* @param typedefType the type possibly containing the typedef as its nested type.
* @return the given type with the nested type replaced by the typedef, or {@code null} if
* the typedefType doesn't contain a typedef or the nested type doesn't match the typedef.
*/
public static IType substituteTypedef(IType type, IType typedefType) {
typedefType = getNestedType(typedefType, REF | ALLCVQ | PTR | ARRAY);
if (!(typedefType instanceof ITypedef))
return null;
IType nestedType = getNestedType(type, REF | ALLCVQ | PTR | ARRAY);
if (!nestedType.isSameType(((ITypedef) typedefType).getType()))
return null;
IType result = null;
ITypeContainer containerType = null;
for (IType t = type; ; t = containerType.getType()) {
IType newType = t == nestedType ? typedefType : (IType) t.clone();
if (result == null)
result = newType;
if (containerType != null) {
containerType.setType(newType);
}
if (t == nestedType)
return result;
if (!(t instanceof ITypeContainer))
return null;
containerType = (ITypeContainer) t;
}
}
public static IType mapToAST(IType type, IASTNode node) { public static IType mapToAST(IType type, IASTNode node) {
if (type instanceof IFunctionType) { if (type instanceof IFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type; final ICPPFunctionType ft = (ICPPFunctionType) type;