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 1ca040fd7e4..37b54bb528b 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 @@ -256,7 +256,7 @@ public class AST2CPPTests extends AST2TestBase { assertNotNull(second); assertTrue("Expected types to be the same, but first was: '" + first.toString() + "' and second was: '" + second + "'", first.isSameType(second)); } - + // int *zzz1 (char); // int (*zzz2) (char); // int ((*zzz3)) (char); @@ -9062,6 +9062,13 @@ public class AST2CPPTests extends AST2TestBase { public void testSizeofReference_397342() throws Exception { parseAndCheckBindings(); } + + // constexpr int waldo = sizeof("cat\b\\\n"); + public void testSizeofStringLiteralWithEscapeCharacters_459279() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPVariable waldo = helper.assertNonProblem("waldo"); + assertConstantValue(7, waldo); // "cat" + backspace + slash + newline + null terminator + } // struct A { // char a[100]; @@ -10666,7 +10673,7 @@ public class AST2CPPTests extends AST2TestBase { public void testIsBaseOf_409100() throws Exception { BindingAssertionHelper b = getAssertionHelper(); IVariable var = b.assertNonProblem("value"); - assertEquals(1 /*true */, var.getInitialValue().numericalValue().longValue()); + assertConstantValue(1 /*true */, var); } // namespace NS { @@ -10982,7 +10989,7 @@ public class AST2CPPTests extends AST2TestBase { public void testConditionalExpressionFolding_429891() throws Exception { BindingAssertionHelper helper = getAssertionHelper(); IVariable waldo = helper.assertNonProblem("waldo"); - assertEquals(5, waldo.getInitialValue().numericalValue().longValue()); + assertConstantValue(5, waldo); } // constexpr int naive_fibonacci(int x) { @@ -11009,7 +11016,7 @@ public class AST2CPPTests extends AST2TestBase { public void testNameLookupInDefaultArgument_432701() throws Exception { BindingAssertionHelper helper = getAssertionHelper(); IVariable waldo = helper.assertNonProblem("waldo"); - assertEquals(42, waldo.getInitialValue().numericalValue().longValue()); + assertConstantValue(42, waldo); } // struct S1 { S1(int); }; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 718be54a614..75a6432cfe8 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -3071,7 +3071,7 @@ public class AST2TemplateTests extends AST2TestBase { ICPPVariable _256= ba.assertNonProblem("_256=0x100", 4, ICPPVariable.class); IQualifierType qt1= assertInstance(_256.getType(), IQualifierType.class); ICPPBasicType bt1= assertInstance(qt1.getType(), ICPPBasicType.class); - assertEquals(256, _256.getInitialValue().numericalValue().intValue()); + assertConstantValue(256, _256); ICPPVariable t= ba.assertNonProblem("t;", 1, ICPPVariable.class); ICPPTemplateInstance ci1= assertInstance(t.getType(), ICPPTemplateInstance.class, ICPPClassType.class); @@ -7390,9 +7390,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testSfinaeInNestedTypeInTemplateArgument_402257() throws Exception { BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); ICPPVariable B = helper.assertNonProblem("B"); - Long val = B.getInitialValue().numericalValue(); - assertNotNull(val); - assertEquals(0 /* false */, val.longValue()); + assertConstantValue(0 /* false */, B); } // struct S { @@ -8038,9 +8036,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testSizeofParameterPackOnTypeid_401973() throws Exception { BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); ICPPVariable bar = helper.assertNonProblem("bar"); - Long barValue = bar.getInitialValue().numericalValue(); - assertNotNull(barValue); - assertEquals(2, barValue.longValue()); + assertConstantValue(2, bar); } // template struct tuple_indices {}; @@ -8573,7 +8569,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testSpecializationOfConstexprFunction_420995() throws Exception { BindingAssertionHelper helper = getAssertionHelper(); ICPPVariable waldo = helper.assertNonProblem("waldo"); - assertEquals(2, waldo.getInitialValue().numericalValue().longValue()); + assertConstantValue(2, waldo); } // struct Test { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java index 13fdbffc576..40794207cd5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java @@ -60,6 +60,7 @@ import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; @@ -494,6 +495,14 @@ public class AST2TestBase extends BaseTestCase { assertEquals(ownerName, struct.getName()); } + protected static void assertConstantValue(long expected, IVariable constant) { + IValue value = constant.getInitialValue(); + assertNotNull(value); + Long numericalValue = value.numericalValue(); + assertNotNull(numericalValue); + assertEquals(expected, numericalValue.longValue()); + } + protected class BindingAssertionHelper { protected IASTTranslationUnit tu; protected String contents; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java index 9a9391c2ff9..c97b28a75a7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java @@ -42,6 +42,7 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx private int kind; private char[] value = CharArrayUtils.EMPTY; + private int fStringLiteralSize = -1; // accounting for escape sequences and the null terminator private ICPPEvaluation fEvaluation; public CPPASTLiteralExpression() { @@ -110,31 +111,73 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx return true; } - private IValue getStringLiteralSize() { - char[] value= getValue(); - int length= value.length-1; - boolean isRaw= false; - for (int i = 0; i < length; i++) { - final char c = value[i]; - if (c == '"') { - if (isRaw) { - for (int j = i + 1; j < length; j++) { - final char d= value[j]; - if (d == '(') { - length -= 2*(j-i); - break; - } - } - } - length -= i; - if (length < 0) - length = 0; - break; - } else if (c == 'R') { - isRaw = true; + private int computeStringLiteralSize() { + int start = 0, end = value.length - 1; + boolean isRaw = false; + + // Skip past a prefix affecting the character type. + if (value[0] == 'L' || value[0] == 'u' || value[0] == 'U') { + ++start; + } + + // If there is an 'R' prefix, skip past it but take note of it. + if (value[start] == 'R') { + ++start; + isRaw = true; + } + + // Now we should have a quote-enclosed string. Skip past the quotes. + if (!(value[start] == '"' && value[end] == '"')) { + // Unexpected! + return 0; + } + ++start; + --end; + + // If we have a raw string, skip past the raw prefix. + if (isRaw) { + while (value[start] != '(' && start <= end) { + ++start; + --end; + } + + // Now we should have a parenthesis-enclosed string. + if (!(value[start] == '(' && value[end] == ')')) { + // Unexpected! + return 0; + } + + // Since the string is raw, we don't need to process + // escape sequences, so the size is just the number + // of remaining characters, plus 1 for the null terminator. + return (end - start + 1) + 1; + } + + // Otherwise, we have a non-raw string and we need to + // process escape sequences. + int length = 0; + boolean escaping = false; + for (; start <= end; ++start) { + if (escaping) { + escaping = false; + ++length; + } else if (value[start] == '\\') { + escaping = true; + } else { + ++length; } + // TODO: Handle fancier things like octal literals. + } + + // + 1 for null terminator. + return length + 1; + } + + private IValue getStringLiteralSize() { + if (fStringLiteralSize == -1) { + fStringLiteralSize = computeStringLiteralSize(); } - return Value.create(length); + return Value.create(fStringLiteralSize); } private Kind getCharType() {