diff options
author | Nathan Ridge | 2018-02-13 22:36:26 +0000 |
---|---|---|
committer | Nathan Ridge | 2018-02-20 06:15:52 +0000 |
commit | d8a9bdddb551fceaf0819b9655edc187aeba5fc9 (patch) | |
tree | d4ace4146ae02543dba6b830193a41584494e97c | |
parent | 13ecd568b3a1da85d6731cf6934e0c81acf4e9bc (diff) | |
download | org.eclipse.cdt-d8a9bdddb551fceaf0819b9655edc187aeba5fc9.tar.gz org.eclipse.cdt-d8a9bdddb551fceaf0819b9655edc187aeba5fc9.tar.xz org.eclipse.cdt-d8a9bdddb551fceaf0819b9655edc187aeba5fc9.zip |
Bug 527844: ExpressionWriter does not write IASTLiteralExpression suffix
Change-Id: I5f5e120b1deea4ac33a2170cad0f454ab27871e2
Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch>
7 files changed, 480 insertions, 349 deletions
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 ee434fc2da8..e7c1c2b670f 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 @@ -12025,6 +12025,39 @@ public class AST2CPPTests extends AST2CPPTestBase { assertEquals(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, problems[0].getID()); } + // struct basic_string { + // basic_string(char const * str, int len); + // }; + // basic_string operator""s(char const * str, int len) { + // return basic_string { str, len }; + // } + // auto waldo = "Waldo"s; + public void testStringLiterals() throws Exception { + checkUserDefinedLiteralIsType(getAboveComment(), "basic_string"); + } + + // auto waldo = 1i + 1; + public void testComplexNumbersCompilerSupport1() throws Exception { + checkUserDefinedLiteralIsType(getAboveComment(), "_Complex int"); + } + + // auto waldo = 1j + 1; + public void testComplexNumbersCompilerSupport2() throws Exception { + checkUserDefinedLiteralIsType(getAboveComment(), "_Complex int"); + } + + // struct complex { + // complex(unsigned long long real, unsigned long long imag); + // complex operator+(unsigned long long); + // }; + // complex operator""i(unsigned long long imag) { + // return complex { 0, imag }; + // } + // auto waldo = 1i + 1; + public void testComplexNumbersOverriddenCompilerSupport() throws Exception { + checkUserDefinedLiteralIsType(getAboveComment(), "complex"); + } + // // Test name lacking a space // int operator ""X(const char* s) { return 0; } // int operator ""_X(const char* s) { return 0; } diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterExpressionTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterExpressionTestSource.awts index b2d0faa9f80..5fb282c1a78 100644 --- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterExpressionTestSource.awts +++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterExpressionTestSource.awts @@ -198,3 +198,22 @@ TestClass* tc = new TestClass(); //%CPP int i = int(1); +//!CPP LiteralExpression with string literal +//%CPP +int main() +{ + using namespace std::string_literals; + auto str = "foobar"s; +} + +//!CPP LiteralExpression with user defined literal +//%CPP +constexpr long double operator ""_deg(long double deg) +{ + return deg * 3.141592 / 180; +} + +int main() +{ + double x = 90.0_deg; +}
\ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java index b5692e2f8cb..4418e803818 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java @@ -175,9 +175,9 @@ public class CharArrayUtils { } public static final char[] concat(char[] first, char[] second) { - if (first == null) + if (first == null || first.length == 0) return second; - if (second == null) + if (second == null || second.length == 0) return first; int length1 = first.length; 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 e63804a94c8..e1843b984ae 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 @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) * Richard Eames + * Hansruedi Patzen (IFS) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -24,6 +25,8 @@ import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IProblemBinding; +import org.eclipse.cdt.core.dom.ast.IProblemType; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; @@ -55,30 +58,48 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx private static final EvalFixed EVAL_FALSE = new EvalFixed(CPPBasicType.BOOLEAN, PRVALUE, IntegralValue.create(false)); private static final EvalFixed EVAL_NULL_PTR = new EvalFixed(CPPBasicType.NULL_PTR, PRVALUE, IntegralValue.create(0)); - public static final CPPASTLiteralExpression INT_ZERO = - new CPPASTLiteralExpression(lk_integer_constant, new char[] {'0'}); + public static final CPPASTLiteralExpression INT_ZERO = new CPPASTLiteralExpression(lk_integer_constant, new char[] {'0'}); - private int fKind; - private char[] fValue = CharArrayUtils.EMPTY; - private int fStringLiteralSize = -1; // Accounting for escape sequences and the null terminator. - private char[] fSuffix = CharArrayUtils.EMPTY; - private boolean fIsCompilerSuffix = true; - private ICPPEvaluation fEvaluation; + private int fKind; + /** + * The value of a CPPASTLiteralExpression consists of a literal and a suffix. + * + * E.g. 1f -> literal: 1 suffix: f + * 1ull -> literal: 1 suffix: ull + * 10.0_udl -> literal: 10.0 suffix: _udl + * "waldo"s -> literal: "waldo" suffix: s + * 'a'_udl -> literal: 'a' suffix: _udl + */ + private char[] fLiteral; + private char[] fSuffix; + private final char[] fNumericCompilerSuffixes; + private int fStringLiteralSize; // Accounting for escape sequences and the null terminator. + private ICPPEvaluation fEvaluation; private IBinding fUserDefinedLiteralOperator; private IASTImplicitName[] fImplicitNames; - public CPPASTLiteralExpression() { + public CPPASTLiteralExpression(int kind, char[] value) { + this(kind, value, CharArrayUtils.EMPTY); } - public CPPASTLiteralExpression(int kind, char[] value) { - this.fKind = kind; - this.fValue = value; + public CPPASTLiteralExpression(int kind, char[] value, char[] numericCompilerSuffixes) { + fKind = kind; + fSuffix = getSuffix(kind, value, CharArrayUtils.EMPTY); + fLiteral = getLiteral(value, fSuffix); + fNumericCompilerSuffixes = (numericCompilerSuffixes == null) ? CharArrayUtils.EMPTY : numericCompilerSuffixes; + fStringLiteralSize = -1; } - public CPPASTLiteralExpression(int kind, char[] value, char[] suffix, boolean isCompilerSuffix) { - this(kind, value); - this.setSuffix(suffix); + private CPPASTLiteralExpression(CPPASTLiteralExpression other) { + fKind = other.fKind; + fLiteral = other.fLiteral; + fSuffix = other.fSuffix; + fNumericCompilerSuffixes = other.fNumericCompilerSuffixes; + fStringLiteralSize = other.fStringLiteralSize; + fEvaluation = other.fEvaluation; + fUserDefinedLiteralOperator = other.fUserDefinedLiteralOperator; + fImplicitNames = other.fImplicitNames; } @Override @@ -88,219 +109,257 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx @Override public CPPASTLiteralExpression copy(CopyStyle style) { - CPPASTLiteralExpression copy = new CPPASTLiteralExpression(fKind, - fValue == null ? null : fValue.clone(), - fSuffix == null ? null : fSuffix.clone(), - fIsCompilerSuffix); - copy.setOffsetAndLength(this); - return copy(copy, style); + return copy(new CPPASTLiteralExpression(this), style); } @Override public int getKind() { - return fKind; - } + return fKind; + } - @Override - public void setKind(int value) { - assertNotFrozen(); - fKind = value; - } + @Override + public void setKind(int kind) { + assertNotFrozen(); + set(kind, getValue()); + } - @Override + @Override public char[] getValue() { - return fValue; - } + return CharArrayUtils.concat(fLiteral, fSuffix); + } - @Override + @Override public void setValue(char[] value) { - assertNotFrozen(); - this.fValue= value; - } - - public char[] getSuffix() { - return fSuffix; + assertNotFrozen(); + set(fKind, value); } - public void addSuffix(char[] suffix) { - setSuffix(suffix); - // Make sure fValue reflects the added suffix. - fValue = CharArrayUtils.concat(fValue, suffix); - } - - private void setSuffix(char[] suffix) { - this.fSuffix = suffix; + /** + * Sets the kind, suffix and literal fields of this expression. + * + * @param kind the kind of this literal expression + * @param value the value of this literal expression, + * this gets split into a literal and a suffix + */ + private void set(int kind, char[] value) { + fKind = kind; + fSuffix = getSuffix(kind, value, fSuffix); + fLiteral = getLiteral(value, fSuffix); + resetLazyFields(); } - - public void calculateSuffix() { - this.calculateSuffix(CharArrayUtils.EMPTY); + + /** + * Adds a suffix to this literal expression. + * + * @param suffix the suffix to be added. + */ + public void setSuffix(char[] suffix) { + assertNotFrozen(); + fSuffix = (suffix == null) ? CharArrayUtils.EMPTY : suffix; + resetLazyFields(); } /** - * Returns the suffix of a user-defined literal integer or float - * @param compilerSuffixes + * Resets the lazy evaluated fields. This is needed if any of the other fields change. */ - public void calculateSuffix(char[] compilerSuffixes) { - try { - switch (fKind) { - case lk_float_constant: - case lk_integer_constant: - int udOffset = (fValue[0] == '.' ? afterDecimalPoint(0) : integerLiteral()); - if (udOffset > 0) { - /* - * 2.14.8.1 - * "If a token matches both user-defined-literal and another literal kind, it is - * treated as the latter" - */ - setSuffix(CharArrayUtils.subarray(fValue, udOffset, -1)); - for (int i = 0; i < fSuffix.length; i++) { - switch (fSuffix[i]) { - case 'l': case 'L': - case 'u': case 'U': - case 'f': case 'F': - continue; - } - for (int j = 0; j < compilerSuffixes.length; j++) { - if (fSuffix[i] == compilerSuffixes[j]) { - continue; - } - } - fIsCompilerSuffix = false; - // Remove the suffix from the value if it's a UDL - setValue(CharArrayUtils.subarray(fValue, 0, udOffset)); - break; - } - } - break; - case lk_string_literal: - { - final int offset = CharArrayUtils.lastIndexOf('"', fValue, CharArrayUtils.indexOf('"', fValue) + 1); - if (offset > 0) { - setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1)); - if (fSuffix.length > 0) { - fIsCompilerSuffix = false; - } - } + private void resetLazyFields() { + fStringLiteralSize = -1; + fEvaluation = null; + fUserDefinedLiteralOperator = null; + fImplicitNames = null; + } + + private boolean hasNumericCompilerSuffix() { + if (hasNumericKind() && fSuffix.length == 1) { + for (int j = 0; j < fNumericCompilerSuffixes.length; j++) { + if (fSuffix[0] == fNumericCompilerSuffixes[j]) { + return true; } - break; - case lk_char_constant: - { - final int offset = CharArrayUtils.lastIndexOf('\'', fValue, CharArrayUtils.indexOf('\'', fValue) + 1); - if (offset > 0) { - setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1)); - if (fSuffix.length > 0) { - fIsCompilerSuffix = false; - } - } - } - break; } - } catch (ArrayIndexOutOfBoundsException e) { - // pass } + return false; + } + + private boolean hasNumericKind() { + return fKind == lk_integer_constant || fKind == lk_float_constant; + } + + private static char[] getLiteral(char[] value, char[] suffix) { + if (value == null) { + return CharArrayUtils.EMPTY; + } + if (suffix == null || suffix.length == 0) { + return value; + } + final char[] literal = CharArrayUtils.subarray(value, 0, value.length - suffix.length); + return (literal == null) ? CharArrayUtils.EMPTY : literal; + } + + private static char[] getSuffix(int kind, char[] value, char[] suffix) { + if (value == null || value.length == 0) { + return suffix; + } + int offset = 0; + switch (kind) { + case lk_float_constant: + case lk_integer_constant: + try { + offset = (value[0] == '.') ? afterDecimalPoint(value, 0) : integerLiteral(value); + } catch (ArrayIndexOutOfBoundsException e) { + } + break; + case lk_string_literal: + offset = CharArrayUtils.lastIndexOf('"', value, CharArrayUtils.indexOf('"', value) + 1) + 1; + break; + case lk_char_constant: + offset = CharArrayUtils.lastIndexOf('\'', value, CharArrayUtils.indexOf('\'', value) + 1) + 1; + break; + } + suffix = (offset > 0) ? CharArrayUtils.subarray(value, offset, -1) : suffix; + return (suffix == null) ? CharArrayUtils.EMPTY : suffix; + } + + private boolean hasNumericSuffix() { + final int len = fSuffix.length; + if (!hasSuffix() || !hasNumericKind() || len > 3) { + return false; + } + /* + * 2.14.8.1 + * "If a token matches both user-defined-literal and another literal kind, it is + * treated as the latter" + */ + if (len == 1) { + switch(fSuffix[0]) { + case 'u': case 'U': + case 'f': case 'F': + case 'l': case 'L': + return true; + } + } + if (len == 2) { + switch(fSuffix[0]) { + case 'u': case 'U': + return Character.toLowerCase(fSuffix[1]) == 'l'; + case 'l': case 'L': + return Character.toLowerCase(fSuffix[1]) == 'l' || Character.toLowerCase(fSuffix[1]) == 'u'; + } + } + if (len == 3) { + switch(fSuffix[0]) { + case 'u': case 'U': + return Character.toLowerCase(fSuffix[1]) == 'l' && Character.toLowerCase(fSuffix[2]) == 'l'; + case 'l': case 'L': + return Character.toLowerCase(fSuffix[1]) == 'l' && Character.toLowerCase(fSuffix[2]) == 'u'; + } + } + return false; } @Override public String toString() { - return new String(fValue); - } + return new String(getValue()); + } @Override public IASTImplicitDestructorName[] getImplicitDestructorNames() { return IASTImplicitDestructorName.EMPTY_NAME_ARRAY; // Literal expression does not call destructors. } - @Override + @Override public boolean accept(ASTVisitor action) { - if (action.shouldVisitExpressions) { - switch (action.visit(this)) { - case ASTVisitor.PROCESS_ABORT: return false; - case ASTVisitor.PROCESS_SKIP: return true; - default: break; - } - } - - if (action.shouldVisitImplicitNames) { - for (IASTImplicitName name : getImplicitNames()) { - if (!name.accept(action)) return false; - } - } - - if (action.shouldVisitExpressions) { - switch (action.leave(this)) { - case ASTVisitor.PROCESS_ABORT: return false; - case ASTVisitor.PROCESS_SKIP: return true; - default: break; - } - } - return true; - } - - private int computeStringLiteralSize() { - int start = 0, end = fValue.length - 1 - getSuffix().length; - boolean isRaw = false; - - // Skip past a prefix affecting the character type. - if (fValue[0] == 'L' || fValue[0] == 'u' || fValue[0] == 'U') { - if(fValue[1] == '8') { - ++start; - } - - ++start; - } - - // If there is an 'R' prefix, skip past it but take note of it. - if (fValue[start] == 'R') { - ++start; - isRaw = true; - } - - // Now we should have a quote-enclosed string. Skip past the quotes. - if (!(fValue[start] == '"' && fValue[end] == '"')) { - // Unexpected! - return 0; - } - ++start; - --end; - - // If we have a raw string, skip past the raw prefix. - if (isRaw) { - while (fValue[start] != '(' && start <= end) { - ++start; - --end; - } - - // Now we should have a parenthesis-enclosed string. - if (!(fValue[start] == '(' && fValue[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 (fValue[start] == '\\') { + if (action.shouldVisitExpressions) { + switch (action.visit(this)) { + case ASTVisitor.PROCESS_ABORT: return false; + case ASTVisitor.PROCESS_SKIP: return true; + default: break; + } + } + + if (action.shouldVisitImplicitNames) { + for (IASTImplicitName name : getImplicitNames()) { + if (!name.accept(action)) return false; + } + } + + if (action.shouldVisitExpressions) { + switch (action.leave(this)) { + case ASTVisitor.PROCESS_ABORT: return false; + case ASTVisitor.PROCESS_SKIP: return true; + default: break; + } + } + return true; + } + + private boolean hasSuffix() { + return fSuffix.length > 0; + } + + private int computeStringLiteralSize() { + int start = 0, end = fLiteral.length - 1; + boolean isRaw = false; + + // Skip past a prefix affecting the character type. + if (fLiteral[0] == 'L' || fLiteral[0] == 'u' || fLiteral[0] == 'U') { + if(fLiteral[1] == '8') { + ++start; + } + ++start; + } + + // If there is an 'R' prefix, skip past it but take note of it. + if (fLiteral[start] == 'R') { + ++start; + isRaw = true; + } + + // Now we should have a quote-enclosed string. Skip past the quotes. + if (!(fLiteral[start] == '"' && fLiteral[end] == '"')) { + // Unexpected! + return 0; + } + ++start; + --end; + + // If we have a raw string, skip past the raw prefix. + if (isRaw) { + while (fLiteral[start] != '(' && start <= end) { + ++start; + --end; + } + + // Now we should have a parenthesis-enclosed string. + if (!(fLiteral[start] == '(' && fLiteral[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 (fLiteral[start] == '\\') { escaping = true; } else { ++length; } - // TODO: Handle fancier things like octal literals. - } + // TODO: Handle fancier things like octal literals. + } - // + 1 for null terminator. - return length + 1; - } + // + 1 for null terminator. + return length + 1; + } private IValue getStringLiteralSize() { if (fStringLiteralSize == -1) { @@ -316,18 +375,21 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } private IType getCharType() { - return fSuffix.length > 0 ? getUserDefinedLiteralOperatorType() : new CPPBasicType(getBasicCharKind(), 0, this); - } + return hasSuffix() ? getUserDefinedLiteralOperatorType() : new CPPBasicType(getBasicCharKind(), 0, this); + } private IBinding getUserDefinedLiteralOperator() { - if (!fIsCompilerSuffix && fUserDefinedLiteralOperator == null) { + if (hasSuffix() && !hasNumericSuffix() && fUserDefinedLiteralOperator == null) { try { fUserDefinedLiteralOperator = CPPSemantics.findUserDefinedLiteralOperator(this); + if (fUserDefinedLiteralOperator instanceof IProblemBinding && hasNumericCompilerSuffix()) { + fUserDefinedLiteralOperator = null; + return null; + } } catch (DOMException e) { } if (fUserDefinedLiteralOperator == null) { - fUserDefinedLiteralOperator = new ProblemBinding(this, ISemanticProblem.BINDING_NOT_FOUND, - fSuffix); + fUserDefinedLiteralOperator = new ProblemBinding(this, ISemanticProblem.BINDING_NOT_FOUND, fSuffix); } } return fUserDefinedLiteralOperator; @@ -335,14 +397,12 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx // 13.5.8 private IType getUserDefinedLiteralOperatorType() { - IType ret = new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME); - IBinding func = getUserDefinedLiteralOperator(); if (func != null && func instanceof ICPPFunction) { - ret = ((ICPPFunction) func).getType().getReturnType(); + return ((ICPPFunction) func).getType().getReturnType(); } - return ret; + return new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME); } public char[] getOperatorName() { @@ -350,14 +410,14 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } public Kind getBasicCharKind() { - switch (fValue[0]) { + switch (fLiteral[0]) { case 'L': return Kind.eWChar; case 'U': return Kind.eChar32; case 'u': // Bug 526724 u8 should result in Kind.eChar - if (fValue[1] != '8') { + if (fLiteral[1] != '8') { return Kind.eChar16; } //$FALL-THROUGH$ @@ -367,117 +427,123 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } private IType classifyTypeOfFloatLiteral() { - final char[] lit= fSuffix; - final int len= lit.length; - Kind kind= Kind.eDouble; - int flags= 0; - if (len > 0) { - if (fIsCompilerSuffix) { - switch (lit[len - 1]) { + Kind kind = Kind.eDouble; + int flags = 0; + if (hasSuffix()) { + if (hasNumericSuffix()) { + switch (fSuffix[0]) { case 'f': case 'F': - kind= Kind.eFloat; + kind = Kind.eFloat; break; case 'l': case 'L': flags |= IBasicType.IS_LONG; break; } } else { - return getUserDefinedLiteralOperatorType(); + IType type = getUserDefinedLiteralOperatorType(); + if (type instanceof IProblemType && hasNumericCompilerSuffix()) { + switch (fSuffix[0]) { + case 'i': case 'j': + flags |= IBasicType.IS_IMAGINARY; + break; + } + } else { + return type; + } } } return new CPPBasicType(kind, flags, this); } private IType classifyTypeOfIntLiteral() { - int makelong= 0; - boolean unsigned= false; - final char[] lit= fSuffix; - int flags= 0; - - if (fIsCompilerSuffix) { - for (int i= lit.length - 1; i >= 0; i--) { - final char c= lit[i]; - if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) { - break; + Kind kind = Kind.eInt; + int flags = 0; + + if (hasSuffix()) { + if (hasNumericSuffix()) { + int makelong = 0; + for (char c : fSuffix) { + switch (c) { + case 'u': case 'U': + flags |= IBasicType.IS_UNSIGNED; + break; + case 'l': case 'L': + makelong++; + break; + } } - switch (c) { - case 'u': - case 'U': - unsigned = true; - break; - case 'l': - case 'L': - makelong++; - break; + if (makelong > 1) { + flags |= IBasicType.IS_LONG_LONG; + } else if (makelong == 1) { + flags |= IBasicType.IS_LONG; + } + } else { + IType type = getUserDefinedLiteralOperatorType(); + if (type instanceof IProblemType && hasNumericCompilerSuffix()) { + switch (fSuffix[0]) { + case 'i': case 'j': + flags |= IBasicType.IS_IMAGINARY; + break; + } + } else { + return type; } } - - if (unsigned) { - flags |= IBasicType.IS_UNSIGNED; - } - - if (makelong > 1) { - flags |= IBasicType.IS_LONG_LONG; - } else if (makelong == 1) { - flags |= IBasicType.IS_LONG; - } - } else if (lit.length > 0) { - return getUserDefinedLiteralOperatorType(); } - return new CPPBasicType(Kind.eInt, flags, this); + return new CPPBasicType(kind, flags, this); } - private int integerLiteral() { + private static int integerLiteral(char[] value) { int i = 0; - char c = fValue[i++]; + char c = value[i++]; - if (c == '0' && i < fValue.length) { + if (c == '0' && i < value.length) { // Probably octal/hex/binary - c = fValue[i]; + c = value[i]; switch ((c | 0x20)) { case 'x': - return probablyHex(i); + return probablyHex(value, i); case 'b': - return probablyBinary(i); + return probablyBinary(value, i); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* octal-literal: * 0 * octal-literal octal-digit */ - while (isOctal(c) && i < fValue.length) { - c = fValue[++i]; + while (isOctal(c) && i < value.length) { + c = value[++i]; } break; case '.': - return afterDecimalPoint(i); + return afterDecimalPoint(value, i); } /* * If there is an 8 or 9, then we have a malformed octal */ if (c == '8' || c == '9') { // eat remaining numbers - c = fValue[i]; - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[++i]; + c = value[i]; + while (Character.isDigit(c) && i < value.length) { + c = value[++i]; } } /* * A floating-point constant could also have a leading zero */ - return handleDecimalOrExponent(c, i); + return handleDecimalOrExponent(value, c, i); } else if (Character.isDigit(c)) { /* decimal-literal : * nonzero-digit (c has to be this to get into this else) * decimal-literal digit */ - c = fValue[i]; - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[++i]; + c = value[i]; + while (Character.isDigit(c) && i < value.length) { + c = value[++i]; } - return handleDecimalOrExponent(c, i); + return handleDecimalOrExponent(value, c, i); } else { // Somehow we got called and there wasn't a digit // Shouldn't get here @@ -490,26 +556,26 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx /* * Consumes a decimal point or exponent, if present. */ - private int handleDecimalOrExponent(char c, int i) { + private static int handleDecimalOrExponent(char[] value, char c, int i) { if (c == '.') { - return afterDecimalPoint(i); + return afterDecimalPoint(value, i); } else if ((c | 0x20) == 'e') { - return exponentPart(i); + return exponentPart(value, i); } return i; } /* - * Called with the expectation that fValue[i] == '.' + * Called with the expectation that value[i] == '.' */ - private int afterDecimalPoint(int i) { - char c = fValue[++i]; - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[++i]; + private static int afterDecimalPoint(char[] value, int i) { + char c = value[++i]; + while (Character.isDigit(c) && i < value.length) { + c = value[++i]; } if ((c | 0x20) == 'e') { - return exponentPart(i); + return exponentPart(value, i); } return i; @@ -518,16 +584,16 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx /* * Called with the expectation that c == 'e' */ - private int exponentPart(int i) { - char c = fValue[++i]; + private static int exponentPart(char[] value, int i) { + char c = value[++i]; // optional '+' or '-' if (c == '+' || c == '-') { - c = fValue[++i]; + c = value[++i]; } - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[++i]; + while (Character.isDigit(c) && i < value.length) { + c = value[++i]; } // If there were no digits following the 'e' then we have // D.De or .De which is a UDL on a double @@ -536,21 +602,21 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } // GCC's binary constant notation - private int probablyBinary(int i) { - char c = fValue[++i]; + private static int probablyBinary(char[] value, int i) { + char c = value[++i]; if (c == '1' || c == '0') { - while (c == '1' || c == '0' && i < fValue.length) { - c = fValue[i++]; + while (c == '1' || c == '0' && i < value.length) { + c = value[i++]; } if (Character.isDigit(c)) { // UDL can't begin with digit, so this is a malformed binary return -1; } else if (c == '.') { // no such thing as binary floating point - c = fValue[++i]; - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[i++]; + c = value[++i]; + while (Character.isDigit(c) && i < value.length) { + c = value[i++]; } } } else { @@ -560,22 +626,22 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx return i; } - private int probablyHex(int i) { + private static int probablyHex(char[] value, int i) { /* hexadecimal-literal * 0x hexadecimal-digit * 0X hexadecimal-digit * hexadecimal-literal hexadecimal-digit */ - char c = fValue[++i]; + char c = value[++i]; if (isHexDigit(c)) { - while (isHexDigit(c) && i < fValue.length) { - c = fValue[++i]; + while (isHexDigit(c) && i < value.length) { + c = value[++i]; } if (c == '.') { // Could be GCC's hex float - return hexFloatAfterDecimal(i); + return hexFloatAfterDecimal(value, i); } else if ((c | 0x20) == 'p') { - return hexFloatExponent(i); + return hexFloatExponent(value, i); } } else { return i - 1; @@ -584,17 +650,17 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx return i; } - // Assumes fValue[i] == '.' - private int hexFloatAfterDecimal(int i) { + // Assumes value[i] == '.' + private static int hexFloatAfterDecimal(char[] value, int i) { // 0xHHH. - char c = fValue[++i]; + char c = value[++i]; if (isHexDigit(c)) { - while (isHexDigit(c) && i < fValue.length) { - c = fValue[++i]; + while (isHexDigit(c) && i < value.length) { + c = value[++i]; } if ((c | 0x20) == 'p') { - return hexFloatExponent(i); + return hexFloatExponent(value, i); } else { // The parser is very confused at this point // as the expression is 0x1.f @@ -608,17 +674,17 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } // Assumes image[i] == 'p' - private int hexFloatExponent(int i) { + private static int hexFloatExponent(char[] value, int i) { // 0xHH.HH[pP][-+]?DDDD - char c = fValue[++i]; + char c = value[++i]; if (c == '-' || c == '+') { - c = fValue[++i]; + c = value[++i]; } if (Character.isDigit(c)) { - while (Character.isDigit(c) && i < fValue.length) { - c = fValue[++i]; + while (Character.isDigit(c) && i < value.length) { + c = value[++i]; } } else { return i - 1; @@ -626,28 +692,28 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx return i; } - private boolean isHexDigit(char c) { + private static boolean isHexDigit(char c) { c |= 0x20; return ((c <= 'f' && c >= 'a') || (c <= '9' && c >= '0')); } - private boolean isOctal(final char c) { + private static boolean isOctal(final char c) { return c >= '0' && c <= '7'; } - /** - * @deprecated, use {@link #setValue(char[])}, instead. - */ - @Override + /** + * @deprecated, use {@link #setValue(char[])}, instead. + */ + @Override @Deprecated public void setValue(String value) { - assertNotFrozen(); - this.fValue = value.toCharArray(); - } + assertNotFrozen(); + set(fKind, value.toCharArray()); + } - /** - * @deprecated use {@link #CPPASTLiteralExpression(int, char[])}, instead. - */ + /** + * @deprecated use {@link #CPPASTLiteralExpression(int, char[])}, instead. + */ @Deprecated public CPPASTLiteralExpression(int kind, String value) { this(kind, value.toCharArray()); @@ -656,15 +722,15 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx @Override public ICPPEvaluation getEvaluation() { if (fEvaluation == null) - fEvaluation= createEvaluation(); + fEvaluation = createEvaluation(); return fEvaluation; } private ICPPEvaluation createLiteralEvaluation() { - switch (fKind) { + switch (fKind) { case lk_this: { IScope scope = CPPVisitor.getContainingScope(this); - IType type= CPPVisitor.getImpliedObjectType(scope); + IType type = CPPVisitor.getImpliedObjectType(scope); if (type == null) return EvalFixed.INCOMPLETE; return new EvalFixed(new CPPPointerType(type), PRVALUE, IntegralValue.THIS); @@ -676,15 +742,15 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx case lk_char_constant: return new EvalFixed(getCharType(), PRVALUE, createCharValue()); case lk_float_constant: - return new EvalFixed(classifyTypeOfFloatLiteral(), PRVALUE, FloatingPointValue.create(getValue())); + return new EvalFixed(classifyTypeOfFloatLiteral(), PRVALUE, FloatingPointValue.create(fLiteral)); case lk_integer_constant: return new EvalFixed(classifyTypeOfIntLiteral(), PRVALUE, createIntValue()); case lk_string_literal: - return new EvalFixed(getStringType(), LVALUE, CStringValue.create(getValue())); + return new EvalFixed(getStringType(), LVALUE, CStringValue.create(fLiteral)); case lk_nullptr: return EVAL_NULL_PTR; - } - return EvalFixed.INCOMPLETE; + } + return EvalFixed.INCOMPLETE; } private ICPPEvaluation createEvaluation() { @@ -705,7 +771,7 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } else if (paramCount == 1) { //this means that we need to fall back to the raw literal operator if (params[0].getType() instanceof IPointerType) { - char numValue[] = getValue(); + char numValue[] = fLiteral; int numLen = numValue.length; char strValue[] = new char[numLen + 2]; strValue[0] = '"'; @@ -730,7 +796,7 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx } //has a user-defined literal suffix but didn't find a udl operator function => error - if (getSuffix().length > 0 && (getKind() == lk_string_literal || !fIsCompilerSuffix)) { + if (hasSuffix() && !hasNumericSuffix() && !hasNumericCompilerSuffix()) { return EvalFixed.INCOMPLETE; } @@ -739,10 +805,8 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx private IValue createCharValue() { try { - final char[] image= getValue(); - if (image.length > 1 && image[0] == 'L') - return IntegralValue.create(ExpressionEvaluator.getChar(image, 2)); - return IntegralValue.create(ExpressionEvaluator.getChar(image, 1)); + final int index = (fLiteral.length > 1 && fLiteral[0] == 'L') ? 2 : 1; + return IntegralValue.create(ExpressionEvaluator.getChar(fLiteral, index)); } catch (EvalException e) { return IntegralValue.UNKNOWN; } @@ -750,7 +814,7 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx private IValue createIntValue() { try { - return IntegralValue.create(ExpressionEvaluator.getNumber(getValue())); + return IntegralValue.create(ExpressionEvaluator.getNumber(fLiteral)); } catch (EvalException e) { return IntegralValue.UNKNOWN; } @@ -758,7 +822,7 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx @Override public IType getExpressionType() { - return CPPEvaluation.getType(this); + return CPPEvaluation.getType(this); } @Override @@ -768,20 +832,25 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx @Override public ValueCategory getValueCategory() { - return getKind() == lk_string_literal ? LVALUE : PRVALUE; + return (fKind == lk_string_literal) ? LVALUE : PRVALUE; } @Override public IASTImplicitName[] getImplicitNames() { if (fImplicitNames == null) { - if (fIsCompilerSuffix) { + if (!hasSuffix() || hasNumericSuffix()) { fImplicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { - CPPASTImplicitName operatorName = new CPPASTImplicitName(fSuffix, this); - operatorName.setOperator(true); - operatorName.setBinding(getUserDefinedLiteralOperator()); - operatorName.setOffsetAndLength(getOffset() + fValue.length, fSuffix.length); - fImplicitNames = new IASTImplicitName[] { operatorName }; + IBinding userDefinedLiteralOperator = getUserDefinedLiteralOperator(); + if (userDefinedLiteralOperator == null && hasNumericCompilerSuffix()) { + fImplicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; + } else { + CPPASTImplicitName operatorName = new CPPASTImplicitName(fSuffix, this); + operatorName.setOperator(true); + operatorName.setBinding(userDefinedLiteralOperator); + operatorName.setOffsetAndLength(getOffset() + fLiteral.length, fSuffix.length); + fImplicitNames = new IASTImplicitName[] { operatorName }; + } } } return fImplicitNames; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java index e06ec2566ff..3d14ce346fc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java @@ -549,6 +549,10 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory { return new CPPASTLiteralExpression(kind, rep.toCharArray()); } + public ICPPASTLiteralExpression newLiteralExpression(int kind, String rep, char[] numericCompilerSuffixes) { + return new CPPASTLiteralExpression(kind, rep.toCharArray(), numericCompilerSuffixes); + } + @Override public ICPPASTName newName() { return new CPPASTName(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index b5c724f3730..4ff13c545f0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -1930,18 +1930,30 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { IASTLiteralExpression literalExpr = null; IASTLiteralExpression literalExprWithRange = null; + ICPPNodeFactory nodeFactory = getNodeFactory(); + switch (LT(1)) { case IToken.tINTEGER: t = consume(); - literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage()); + // Fix for bug 527844 adapted to the 9.4 branch only, to avoid API changes. + if (nodeFactory instanceof CPPNodeFactory) { + literalExpr = ((CPPNodeFactory) nodeFactory) + .newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage(), additionalNumericalSuffixes); + } else { + literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage()); + } literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset()); - ((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes); break; case IToken.tFLOATINGPT: t = consume(); - literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage()); + // Fix for bug 527844 adapted to the 9.4 branch only, to avoid API changes. + if (nodeFactory instanceof CPPNodeFactory) { + literalExpr = ((CPPNodeFactory) nodeFactory) + .newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage(), additionalNumericalSuffixes); + } else { + literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage()); + } literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset()); - ((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes); break; case IToken.tSTRING: case IToken.tLSTRING: @@ -1949,9 +1961,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.tUTF32STRING: case IToken.tUSER_DEFINED_STRING_LITERAL: literalExprWithRange = stringLiteral(); - if (supportUserDefinedLiterals) { - ((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix(); - } break; case IToken.tCHAR: case IToken.tLCHAR: @@ -1962,9 +1971,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { literalExpr = getNodeFactory().newLiteralExpression( IASTLiteralExpression.lk_char_constant, t.getImage()); literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset()); - if (supportUserDefinedLiterals) { - ((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix(); - } break; case IToken.t_false: t = consume(); @@ -2033,7 +2039,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return literalExprWithRange; } IToken opName = consume(IToken.tIDENTIFIER); - ((CPPASTLiteralExpression) literalExprWithRange).addSuffix(opName.getCharImage()); + ((CPPASTLiteralExpression) literalExprWithRange).setSuffix(opName.getCharImage()); setRange(literalExprWithRange, offset, opName.getEndOffset()); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/AccessorFactory.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/AccessorFactory.java index ce8c38c5eb2..4dda7b85b9f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/AccessorFactory.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/AccessorFactory.java @@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTArrayDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; import org.eclipse.cdt.core.dom.rewrite.TypeHelper; import org.eclipse.cdt.core.parser.Keywords; @@ -220,8 +221,7 @@ public abstract class AccessorFactory { CPPASTName parameterName = getSetterParameterName(); if (Arrays.equals(fieldName.getSimpleID(), parameterName.getSimpleID())) { CPPASTFieldReference fieldRef = new CPPASTFieldReference(); - CPPASTLiteralExpression litExpr = new CPPASTLiteralExpression(); - litExpr.setValue(Keywords.cTHIS); + CPPASTLiteralExpression litExpr = new CPPASTLiteralExpression(ICPPASTLiteralExpression.lk_this, Keywords.cTHIS); fieldRef.setFieldOwner(litExpr); fieldRef.setIsPointerDereference(true); fieldRef.setFieldName(fieldName.copy(CopyStyle.withLocations)); |