diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java index 4b1777864bc..ed3edc18d69 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) * Mike Kucera (IBM) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -628,6 +629,23 @@ public class AST2BaseTest extends BaseTestCase { return selector.findImplicitName(offset, len); } + public T assertNode(String context, String nodeText, Class 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 assertNode(String nodeText, Class type, Class... cs) { + return assertNode(contents, nodeText, type, cs); + } + private String renderProblemID(int i) { try { for (Field field : IProblemBinding.class.getDeclaredFields()) { @@ -652,17 +670,31 @@ public class AST2BaseTest extends BaseTestCase { IBinding binding= binding(section, len); assertTrue("ProblemBinding for name: " + section.substring(0, len), !(binding instanceof IProblemBinding)); - assertInstance(binding, type); - for (Class c : cs) { - assertInstance(binding, c); - } - return type.cast(binding); + return assertType(binding, type, cs); } - + + public T assertNonProblem(String section, Class type, Class... cs) { + return assertNonProblem(section, section.length(), type, cs); + } + + public T assertNonProblem(String context, String name, Class type, Class... cs) { + IBinding binding= binding(context, name); + assertTrue("ProblemBinding for name: " + name, !(binding instanceof IProblemBinding)); + return assertType(binding, type, cs); + } + + public U assertType(T obj, Class type, Class... cs) { + assertInstance(obj, type); + for (Class c : cs) { + assertInstance(obj, c); + } + return type.cast(obj); + } + private IBinding binding(String section, int len) { IASTName name = findName(section, len); final String selection = section.substring(0, len); - assertNotNull("did not find \"" + selection + "\"", name); + assertNotNull("Did not find \"" + selection + "\"", name); assertEquals(selection, name.getRawSignature()); IBinding binding = name.resolveBinding(); @@ -670,7 +702,17 @@ public class AST2BaseTest extends BaseTestCase { 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 { return parseAndCheckBindings(code, lang, false); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index c1bb59c1559..a2773522dc5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -4705,6 +4705,33 @@ public class AST2CPPTests extends AST2BaseTest { assertSame(i, col.getName(7).resolveBinding()); } + // template + // class basic_string { + // basic_string& operator+=(const T* s); + // }; + // + // template + // basic_string operator+(const T* cs, const basic_string& s); + // + // template + // basic_string operator+(const basic_string& s, const T* cs); + // + // typedef basic_string 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() { // return 5; // } @@ -4979,7 +5006,7 @@ public class AST2CPPTests extends AST2BaseTest { // void f2() { // f1(__null); // } - public void testBug240567() throws Exception { + public void testBug240567() throws Exception { BindingAssertionHelper bh= getAssertionHelper(); bh.assertNonProblem("f1(__null", 2, ICPPFunction.class); } 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 e8479a2a0e6..d76d3e9fbdf 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 @@ -9,6 +9,7 @@ * Doug Schaefer (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ 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; // int a= TInt; //ref public void testTypeAsExpressionIsProblem_261175() throws Exception { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTBinaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTBinaryExpression.java index d40707ddac7..bab886728ae 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTBinaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTBinaryExpression.java @@ -9,9 +9,12 @@ * John Camelon (IBM Rational Software) - Initial API and implementation * Yuan Zhang / Beth Tibbitts (IBM Research) * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ 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.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; @@ -207,11 +210,13 @@ public class CASTBinaryExpression extends ASTNode @Override public IType getExpressionType() { final int op = getOperator(); - final IType t1= CVisitor.unwrapTypedefs(getOperand1().getExpressionType()); - final IType t2= CVisitor.unwrapTypedefs(getOperand2().getExpressionType()); - IType type= CArithmeticConversion.convertCOperandTypes(op, t1, t2); + IType originalType1 = getOperand1().getExpressionType(); + IType originalType2 = getOperand2().getExpressionType(); + final IType type1= CVisitor.unwrapTypedefs(originalType1); + final IType type2= CVisitor.unwrapTypedefs(originalType2); + IType type= CArithmeticConversion.convertCOperandTypes(op, type1, type2); if (type != null) { - return type; + return restoreTypedefs(type, originalType1, originalType2); } switch (op) { @@ -226,25 +231,25 @@ public class CASTBinaryExpression extends ASTNode return new CBasicType(Kind.eInt, 0, this); case IASTBinaryExpression.op_plus: - if (t1 instanceof IArrayType) { - return arrayTypeToPointerType((ICArrayType) t1); - } else if (t2 instanceof IPointerType) { - return t2; - } else if (t2 instanceof IArrayType) { - return arrayTypeToPointerType((ICArrayType) t2); + if (type1 instanceof IArrayType) { + return arrayTypeToPointerType((ICArrayType) type1); + } else if (type2 instanceof IPointerType) { + return restoreTypedefs(type2, originalType2); + } else if (type2 instanceof IArrayType) { + return arrayTypeToPointerType((ICArrayType) type2); } break; case IASTBinaryExpression.op_minus: - if (t2 instanceof IPointerType || t2 instanceof IArrayType) { - if (t1 instanceof IPointerType || t1 instanceof IArrayType) { + if (type2 instanceof IPointerType || type2 instanceof IArrayType) { + if (type1 instanceof IPointerType || type1 instanceof IArrayType) { return CVisitor.getPtrDiffType(this); } - return t1; + return restoreTypedefs(type1, originalType1); } break; } - return t1; + return restoreTypedefs(type1, originalType1); } private IType arrayTypeToPointerType(ICArrayType type) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTUnaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTUnaryExpression.java index 6bd1a077232..7d06b0dd0c1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTUnaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTUnaryExpression.java @@ -9,9 +9,12 @@ * John Camelon (IBM Rational Software) - Initial API and implementation * Yuan Zhang / Beth Tibbitts (IBM Research) * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ 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.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTNode; @@ -122,17 +125,17 @@ public class CASTUnaryExpression extends ASTNode implements IASTUnaryExpression, } break; case op_amper: - return new CPointerType(type, 0); + return new CPointerType(exprType, 0); case op_minus: case op_plus: case op_tilde: IType t= CArithmeticConversion.promoteCType(type); if (t != null) { - return t; + return restoreTypedefs(t, exprType); } break; } - return exprType; // return the original + return exprType; // Return the original. } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java index 0c98534b635..a6a29f4401c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java @@ -9,6 +9,7 @@ * John Camelon (IBM) - Initial API and implementation * Mike Kucera (IBM) * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ 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.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.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.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.CPPVisitor; - public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent { private int op; private IASTExpression operand1; @@ -313,21 +314,26 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr } private IType createExpressionType() { + IType originalType1 = operand1.getExpressionType(); + IType originalType2 = operand2 instanceof IASTExpression ? + ((IASTExpression) operand2).getExpressionType() : null; + // Check for overloaded operator. ICPPFunction o= getOverload(); if (o != null) { - return typeFromFunctionCall(o); + IType type = typeFromFunctionCall(o); + return restoreTypedefs(type, originalType1, originalType2); } final int op = getOperator(); - IType type1 = prvalueType(operand1.getExpressionType()); + IType type1 = prvalueType(originalType1); if (type1 instanceof ISemanticProblem) { return type1; } - + IType type2 = null; - if (operand2 instanceof IASTExpression) { - type2= prvalueType(((IASTExpression) operand2).getExpressionType()); + if (originalType2 != null) { + type2= prvalueType(originalType2); if (type2 instanceof ISemanticProblem) { return type2; } @@ -335,7 +341,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr IType type= CPPArithmeticConversion.convertCppOperandTypes(op, type1, type2); if (type != null) { - return type; + return restoreTypedefs(type, originalType1, originalType2); } switch (op) { @@ -351,10 +357,10 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr case IASTBinaryExpression.op_plus: if (type1 instanceof IPointerType) { - return type1; + return restoreTypedefs(type1, originalType1); } if (type2 instanceof IPointerType) { - return type2; + return restoreTypedefs(type2, originalType2); } break; @@ -363,7 +369,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr if (type2 instanceof IPointerType) { return CPPVisitor.getPointerDiffType(this); } - return type1; + return restoreTypedefs(type1, originalType1); } break; @@ -380,6 +386,6 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr } return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); } - return type1; + return restoreTypedefs(type1, originalType1); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java index 1b732bb14d0..e80a54287ac 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java @@ -72,13 +72,9 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres @Override public CPPASTUnaryExpression copy(CopyStyle style) { - CPPASTUnaryExpression copy = new CPPASTUnaryExpression(op, operand == null ? null - : operand.copy(style)); - copy.setOffsetAndLength(this); - if (style == CopyStyle.withLocations) { - copy.setCopyLocation(this); - } - return copy; + CPPASTUnaryExpression copy = + new CPPASTUnaryExpression(op, operand == null ? null : operand.copy(style)); + return copy(copy, style); } @Override 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 edff05c939e..62279584e4b 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 @@ -2065,6 +2065,9 @@ public class CPPVisitor extends ASTQueries { return new ProblemType(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE); } type = argument.getTypeValue(); + IType t = SemanticUtil.substituteTypedef(type, initType); + if (t != null) + type = t; if (initClause instanceof ICPPASTInitializerList) { type = (IType) CPPTemplates.instantiate(initializer_list_template, new ICPPTemplateArgument[] { new CPPTemplateArgument(type) }); 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 66431d14421..6ae940c814c 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,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.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; @@ -179,7 +188,7 @@ public class Conversions { return cost; } } - // — otherwise, the program is ill-formed. + // � otherwise, the program is ill-formed. return Cost.NO_CONVERSION; } @@ -1147,18 +1156,18 @@ public class Conversions { * 4.1, 4.2, 4.3 */ public static IType lvalue_to_rvalue(IType type) { - type= SemanticUtil.getNestedType(type, TDEF | REF); - if (type instanceof IArrayType) { - return new CPPPointerType(((IArrayType) type).getType()); + IType t= SemanticUtil.getNestedType(type, TDEF | REF); + if (t instanceof IArrayType) { + return new CPPPointerType(((IArrayType) t).getType()); } - if (type instanceof IFunctionType) { - return new CPPPointerType(type); + if (t instanceof IFunctionType) { + return new CPPPointerType(t); } - IType uqType= SemanticUtil.getNestedType(type, TDEF | REF | ALLCVQ); + IType uqType= SemanticUtil.getNestedType(t, TDEF | REF | ALLCVQ); if (uqType instanceof ICPPClassType) { - return type; + return SemanticUtil.getNestedType(type, COND_TDEF | REF); } - return uqType; + return SemanticUtil.getNestedType(t, COND_TDEF | REF | ALLCVQ); } /** diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java index 6f4565f3ee6..0f4be05ea7f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java @@ -7,9 +7,11 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ 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.REF; 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; /** - * Methods for computing the type of an expression + * Methods for computing the type of an expression. */ public class ExpressionTypes { public static IType glvalueType(IType type) { // Reference types are removed. - return SemanticUtil.getNestedType(type, TDEF | REF); + return SemanticUtil.getNestedType(type, COND_TDEF | REF); } public static IType prvalueType(IType type) { @@ -65,46 +67,46 @@ public class ExpressionTypes { return typeFromReturnType(ft.getReturnType()); } - public static IType typeFromReturnType(IType r) { - r= SemanticUtil.getNestedType(r, TDEF); - if (r instanceof ICPPReferenceType) { - return glvalueType(r); + public static IType typeFromReturnType(IType type) { + IType t= SemanticUtil.getNestedType(type, TDEF); + if (t instanceof ICPPReferenceType) { + return glvalueType(type); } - return prvalueType(r); + return prvalueType(type); } - public static IType typeOrFunctionSet(IASTExpression e) { - FunctionSetType fs= getFunctionSetType(e); + public static IType typeOrFunctionSet(IASTExpression exp) { + FunctionSetType fs= getFunctionSetType(exp); if (fs != null) { return fs; } - return e.getExpressionType(); + return exp.getExpressionType(); } - public static ValueCategory valueCat(IASTExpression e) { - FunctionSetType fs= getFunctionSetType(e); + public static ValueCategory valueCat(IASTExpression exp) { + FunctionSetType fs= getFunctionSetType(exp); if (fs != null) return fs.getValueCategory(); - return e.getValueCategory(); + return exp.getValueCategory(); } - private static FunctionSetType getFunctionSetType(IASTExpression e) { + private static FunctionSetType getFunctionSetType(IASTExpression exp) { boolean addressOf= false; - while (e instanceof IASTUnaryExpression) { - final IASTUnaryExpression unary = (IASTUnaryExpression) e; + while (exp instanceof IASTUnaryExpression) { + final IASTUnaryExpression unary = (IASTUnaryExpression) exp; final int op= unary.getOperator(); if (op == IASTUnaryExpression.op_bracketedPrimary) { - e= unary.getOperand(); + exp= unary.getOperand(); } else if (!addressOf && op == IASTUnaryExpression.op_amper) { addressOf= true; - e= unary.getOperand(); + exp= unary.getOperand(); } else { break; } } - if (e instanceof IASTIdExpression) { - IASTIdExpression idexpr= (IASTIdExpression) e; + if (exp instanceof IASTIdExpression) { + IASTIdExpression idexpr= (IASTIdExpression) exp; final IASTName name = idexpr.getName(); IBinding b= name.resolvePreBinding(); if (b instanceof CPPFunctionSet) { @@ -113,4 +115,23 @@ public class ExpressionTypes { } 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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java index 7513e44aec7..fea27bfaa2e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java @@ -14,7 +14,14 @@ *******************************************************************************/ 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.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; /** - * + * Collection of static methods operating on C++ bindings. */ public class SemanticUtil { private static final char[] OPERATOR_CHARS = Keywords.OPERATOR.toCharArray(); // Cache of overloadable operator names for fast lookup. Used by isConversionOperator. private static final CharArraySet cas= new CharArraySet(OverloadableOperator.values().length); - - public static final int TDEF = 0x01; - public static final int REF = 0x02; - public static final int CVTYPE = 0x04; - public static final int ALLCVQ= 0x08; - public static final int PTR= 0x10; - public static final int MPTR= 0x20; - public static final int ARRAY= 0x40; + + // Resolve typedefs. + public static final int TDEF = 0x01; + // Resolve typedefs, but only if necessary for a nested type transformation. + public static final int COND_TDEF = 0x02; + public static final int REF = 0x04; + public static final int CVTYPE = 0x08; + 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 { final int OPERATOR_SPC= OPERATOR_CHARS.length + 1; @@ -221,14 +231,25 @@ public class SemanticUtil { */ public static IType getNestedType(IType type, int options) { final boolean tdef= (options & TDEF) != 0; + final boolean cond_tdef= (options & COND_TDEF) != 0; final boolean ptr= (options & PTR) != 0; final boolean mptr= (options & MPTR) != 0; final boolean allcvq= (options & ALLCVQ) != 0; final boolean cvtype = (options & CVTYPE) != 0; + IType beforeTypedefs = null; + while (true) { 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; if ((ptr && !isMbrPtr) || (mptr && isMbrPtr)) { t= ((IPointerType) type).getType(); @@ -244,20 +265,20 @@ public class SemanticUtil { } return pt; } - } else if (tdef && type instanceof ITypedef) { - t= ((ITypedef) type).getType(); } else if (type instanceof IQualifierType) { + beforeTypedefs = null; final IQualifierType qt = (IQualifierType) type; final IType qttgt = qt.getType(); if (allcvq || cvtype) { t= qttgt; - } else if (tdef) { + } else if (tdef || cond_tdef) { t= getNestedType(qttgt, options); if (t == qttgt) return qt; return addQualifiers(t, qt.isConst(), qt.isVolatile(), false); } } else if (type instanceof IArrayType) { + beforeTypedefs = null; final IArrayType atype= (IArrayType) type; if ((options & ARRAY) != 0) { t= atype.getType(); @@ -269,11 +290,12 @@ public class SemanticUtil { return replaceNestedType((ITypeContainer) atype, newNested); } } else if (type instanceof ICPPReferenceType) { + beforeTypedefs = null; final ICPPReferenceType rt = (ICPPReferenceType) type; if ((options & REF) != 0) { t= rt.getType(); } 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 newNested = getNestedType(nested, TDEF); if (nested == newNested) @@ -282,8 +304,12 @@ public class SemanticUtil { } } // 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; + } type= t; } @@ -354,7 +380,7 @@ public class SemanticUtil { if (newNestedType == null) return type; - // bug 249085 make sure not to add unnecessary qualifications + // Bug 249085 make sure not to add unnecessary qualifications if (type instanceof IQualifierType) { IQualifierType qt= (IQualifierType) type; return addQualifiers(newNestedType, qt.isConst(), qt.isVolatile(), false); @@ -364,7 +390,41 @@ public class SemanticUtil { type.setType(newNestedType); 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) { if (type instanceof IFunctionType) { final ICPPFunctionType ft = (ICPPFunctionType) type;