Bug 527844: ExpressionWriter does not write IASTLiteralExpression suffix

Change-Id: I4dbca527a16c698d7f1a16f2a6a0eca2e6cdc77a
Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch>
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 0ab6bd5..9f78539 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 @@
 		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 b2d0faa..5fb282c 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 @@
 //%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/dom/ast/cpp/ICPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
index 5e3d7c2..819c020 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
@@ -223,6 +223,11 @@
 	@Override
 	public ICPPASTLiteralExpression newLiteralExpression(int kind, String rep);
 
+	/**
+	 * @since 6.5
+	 */
+	public ICPPASTLiteralExpression newLiteralExpression(int kind, String rep, char[] numericCompilerSuffixes);
+
 	public ICPPASTNamespaceAlias newNamespaceAlias(IASTName alias, IASTName qualifiedName);
 
 	public ICPPASTNamespaceDefinition newNamespaceDefinition(IASTName name);
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 b5692e2..4418e80 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 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 e63804a..e1843b9 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.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 @@
 	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 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.fKind = kind;
-		this.fValue = value;
+		this(kind, value, CharArrayUtils.EMPTY);
 	}
 
-	public CPPASTLiteralExpression(int kind, char[] value, char[] suffix, boolean isCompilerSuffix) {
-		this(kind, value);
-		this.setSuffix(suffix);
+	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;
+	}
+
+	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 @@
 
 	@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;
-	}
-
-    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;
-	}
-
-	public void calculateSuffix() {
-		this.calculateSuffix(CharArrayUtils.EMPTY);
+		assertNotFrozen();
+		set(fKind, value);
 	}
 
 	/**
-	 * Returns the suffix of a user-defined literal integer or float
-	 * @param compilerSuffixes
+	 * 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
 	 */
-	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;
-					}
+	private void set(int kind, char[] value) {
+		fKind = kind;
+		fSuffix = getSuffix(kind, value, fSuffix);
+		fLiteral = getLiteral(value, fSuffix);
+		resetLazyFields();
+	}
+	
+	/**
+	 * 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();
+	}
+
+	/**
+	 * Resets the lazy evaluated fields. This is needed if any of the other fields change.
+	 */
+	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_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;
-						}
-					}
-				}
-				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.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;
-	        }
+		if (action.shouldVisitImplicitNames) {
+			for (IASTImplicitName name : getImplicitNames()) {
+				if (!name.accept(action)) return false;
+			}
 		}
-        return true;
-    }
 
-    private int computeStringLiteralSize() {
-    	int start = 0, end = fValue.length - 1 - getSuffix().length;
-    	boolean isRaw = false;
+		if (action.shouldVisitExpressions) {
+			switch (action.leave(this)) {
+				case ASTVisitor.PROCESS_ABORT: return false;
+				case ASTVisitor.PROCESS_SKIP: return true;
+				default: break;
+			}
+		}
+		return true;
+	}
 
-    	// Skip past a prefix affecting the character type.
-    	if (fValue[0] == 'L' || fValue[0] == 'u' || fValue[0] == 'U') {
-    		if(fValue[1] == '8') {
-    			++start;
-    		}
-    		
-    		++start;
-    	}
+	private boolean hasSuffix() {
+		return fSuffix.length > 0;
+	}
 
-    	// If there is an 'R' prefix, skip past it but take note of it.
-    	if (fValue[start] == 'R') {
-    		++start;
-    		isRaw = true;
-    	}
+	private int computeStringLiteralSize() {
+		int start = 0, end = fLiteral.length - 1;
+		boolean isRaw = false;
 
-    	// Now we should have a quote-enclosed string. Skip past the quotes.
-    	if (!(fValue[start] == '"' && fValue[end] == '"')) {
-    		// Unexpected!
-    		return 0;
-    	}
-    	++start;
-    	--end;
+		// 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 we have a raw string, skip past the raw prefix.
-    	if (isRaw) {
-    		while (fValue[start] != '(' && start <= end) {
-    			++start;
-    			--end;
-    		}
+		// 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 parenthesis-enclosed string.
-    		if (!(fValue[start] == '(' && fValue[end] == ')')) {
-    			// Unexpected!
-    			return 0;
-    		}
+		// Now we should have a quote-enclosed string. Skip past the quotes.
+		if (!(fLiteral[start] == '"' && fLiteral[end] == '"')) {
+			// Unexpected!
+			return 0;
+		}
+		++start;
+		--end;
 
-    		// 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;
-    	}
+		// If we have a raw string, skip past the raw prefix.
+		if (isRaw) {
+			while (fLiteral[start] != '(' && start <= end) {
+				++start;
+				--end;
+			}
 
-    	// 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] == '\\') {
+			// 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 @@
 	}
 
 	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 @@
 
 	// 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 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 @@
 	}
 
 	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;
+		Kind kind = Kind.eInt;
+		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;
+		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 @@
 	/*
 	 * 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 @@
 	/*
 	 * 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 @@
 	}
 
 	// 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 @@
 		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 @@
 		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 @@
 	}
 
 	// 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 @@
 		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 @@
 	@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 @@
 		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 @@
 				} 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 @@
 		}
 
 		//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 @@
 
 	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 @@
 
 	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 @@
 
 	@Override
 	public IType getExpressionType() {
-    	return CPPEvaluation.getType(this);
+		return CPPEvaluation.getType(this);
 	}
 
 	@Override
@@ -768,20 +832,25 @@
 
 	@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 e06ec25..acfc73d 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
@@ -550,6 +550,11 @@
 	}
 
 	@Override
+	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 cefa059..b0ce8e6 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
@@ -1931,15 +1931,13 @@
 		switch (LT(1)) {
 		case IToken.tINTEGER:
 			t = consume();
-			literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage());
+			literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage(), additionalNumericalSuffixes);
 			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());
+			literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage(), additionalNumericalSuffixes);
 			literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
-			((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes);
 			break;
 		case IToken.tSTRING:
 		case IToken.tLSTRING:
@@ -1947,9 +1945,6 @@
 		case IToken.tUTF32STRING:
 		case IToken.tUSER_DEFINED_STRING_LITERAL:
 			literalExprWithRange = stringLiteral();
-			if (supportUserDefinedLiterals) {
-				 ((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix();
-			}
 			break;
 		case IToken.tCHAR:
 		case IToken.tLCHAR:
@@ -1960,9 +1955,6 @@
 			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();
@@ -2031,7 +2023,7 @@
 					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 ce8c38c..4dda7b8 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.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 @@
 			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));