1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-19 23:15:24 +02:00

Bug 527954: [C++14] Syntax error when parsing complex udl ""if

With this patch we allow any keyword to be used as a UDL operator, which
for example GCC compiles fine with. They are then no longer highlighted
as keywords but colored the same as normal text. This can be overridden
by coloring overloading operators differently.

Change-Id: If80faf0f3dc599ab4f12fe98977c556aaaefe6aa
Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch>
This commit is contained in:
Hansruedi Patzen 2018-05-15 17:22:34 +02:00 committed by Nathan Ridge
parent a7b0a1fe80
commit dd5c8726a7
5 changed files with 134 additions and 24 deletions

View file

@ -12067,6 +12067,18 @@ public class AST2CPPTests extends AST2CPPTestBase {
checkUserDefinedLiteralIsType(getAboveComment(), "complex");
}
// struct complex {
// complex(long double real, long double imag);
// complex operator+(long double long);
// };
// complex operator""if(long double imag) {
// return complex { 0, imag };
// }
// auto waldo = 1.0if + 1;
public void testComplexFloatNumbersOverriddenCompilerSupport() 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; }

View file

@ -2488,16 +2488,22 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
protected boolean isIdentifierOrKeyword(IToken token) {
char[] image = token.getCharImage();
if (image.length == 0) {
return false;
}
char firstChar = image[0];
return Character.isLetter(firstChar) || firstChar == '_';
}
protected IToken identifierOrKeyword() throws EndOfFileException, BacktrackException {
IToken t = LA(1);
char[] image= t.getCharImage();
if (image.length == 0)
throw backtrack;
char firstChar= image[0];
if (!Character.isLetter(firstChar) && firstChar != '_')
IToken token = LA(1);
if (!isIdentifierOrKeyword(token)) {
throw backtrack;
}
consume();
return t;
return token;
}
/**

View file

@ -912,14 +912,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (strOp.getLength() == 2) {
endOffset = strOp.getEndOffset();
IToken ident = consume(IToken.tIDENTIFIER);
IToken udlOperator = identifierOrKeyword();
char[] operatorName = CharArrayUtils.concat(firstToken.getCharImage(), " ".toCharArray()); //$NON-NLS-1$
operatorName = CharArrayUtils.concat(operatorName, strOp.getCharImage());
operatorName = CharArrayUtils.concat(operatorName, ident.getCharImage());
operatorName = CharArrayUtils.concat(operatorName, udlOperator.getCharImage());
IASTName name = getNodeFactory().newOperatorName(operatorName);
setRange(name, firstToken.getOffset(), ident.getEndOffset());
setRange(name, firstToken.getOffset(), udlOperator.getEndOffset());
return name;
}
break;
@ -2020,13 +2020,13 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IToken la = LA(1);
int offset = ((ASTNode) literalExprWithRange).getOffset();
int length = ((ASTNode) literalExprWithRange).getLength();
if (la.getType() == IToken.tIDENTIFIER) {
if (isIdentifierOrKeyword(la)) {
if ((offset + length) != la.getOffset()) {
return literalExprWithRange;
}
IToken opName = consume(IToken.tIDENTIFIER);
((CPPASTLiteralExpression) literalExprWithRange).setSuffix(opName.getCharImage());
setRange(literalExprWithRange, offset, opName.getEndOffset());
consume();
((CPPASTLiteralExpression) literalExprWithRange).setSuffix(la.getCharImage());
setRange(literalExprWithRange, offset, la.getEndOffset());
}
}

View file

@ -16,8 +16,10 @@ import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.NullProgressMonitor;
@ -92,18 +94,25 @@ public class SemanticHighlightingTest extends TestCase {
return dest;
}
private void enableHighlightingsAndAssignColors() {
private void enableHighlightingsAndAssignColors(Set<String> ignoredHighlightings) {
fColorToPreferenceKeyMap = new HashMap<>();
IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
store.setValue(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED, true);
SemanticHighlighting[] semanticHighlightings= SemanticHighlightings.getSemanticHighlightings();
int blue = 0; // for assigning colors to preferences below
for (SemanticHighlighting semanticHighlighting : semanticHighlightings) {
// Enable the highlighting.
String enabledPreferenceKey = SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting);
if (!store.getBoolean(enabledPreferenceKey))
// Make sure ignored highlightings are disabled.
if (ignoredHighlightings.contains(semanticHighlighting.getPreferenceKey())) {
store.setValue(enabledPreferenceKey, false);
continue;
}
// Enable the highlighting.
if (!store.getBoolean(enabledPreferenceKey)) {
store.setValue(enabledPreferenceKey, true);
}
// Choose a unique color for the highlighting, and save the mapping
// from the color to the highlighting's preference key .
String colorPreferenceKey = SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
@ -129,8 +138,8 @@ public class SemanticHighlightingTest extends TestCase {
// Note: This is not an override of the TestCase.setUp(), but a method called directly
// by the tests, so that they can specify a value for 'isCpp' on a per-test basis.
private void setup(boolean isCpp) throws Exception {
enableHighlightingsAndAssignColors();
private void setup(boolean isCpp, Set<String> ignoredHighlightings) throws Exception {
enableHighlightingsAndAssignColors(ignoredHighlightings);
StringBuilder[] testData = TestSourceReader.getContentsForTest(CTestPlugin.getDefault().getBundle(), "ui", getClass(), getName(), 0);
@ -217,15 +226,23 @@ public class SemanticHighlightingTest extends TestCase {
assertEqualMaps(actual, expected);
}
private void makeAssertions(boolean isCpp) throws Exception {
setup(isCpp);
private void makeAssertions(boolean isCpp, Set<String> ignoredHighlightings) throws Exception {
setup(isCpp, ignoredHighlightings);
try {
doMakeAssertions();
} finally {
teardown();
}
}
private void makeAssertions(Set<String> ignoredHighlightings) throws Exception {
makeAssertions(true, ignoredHighlightings); // default to C++
}
private void makeAssertions(boolean isCpp) throws Exception {
makeAssertions(isCpp, new HashSet<String>());
}
private void makeAssertions() throws Exception {
makeAssertions(true); // default to C++
}
@ -679,4 +696,48 @@ public class SemanticHighlightingTest extends TestCase {
public void testVariablePassedByNonConstRef_529958() throws Exception {
makeAssertions();
}
// float operator""if(long double) { //$functionDeclaration
// return 1.6f;
// }
// int main() { //$functionDeclaration
// auto k = 1.3if; //$localVariableDeclaration,overloadedOperator
// }
public void testOverriddenUDLOperatorIfCall_527954() throws Exception {
makeAssertions();
}
// float operator""if(long double) { //$functionDeclaration
// return 1.6f;
// }
// int main() { //$functionDeclaration
// auto k = 1.3if; //$localVariableDeclaration,c_default
// }
public void testUDLOperatorIfCall_527954() throws Exception {
Set<String> ignoredHighlightings = new HashSet<>();
ignoredHighlightings.add(SemanticHighlightings.OVERLOADED_OPERATOR);
makeAssertions(ignoredHighlightings);
}
// int operator""int(long double) { //$functionDeclaration
// return -1;
// }
// int main() { //$functionDeclaration
// auto k = 1.3int; //$localVariableDeclaration,overloadedOperator
// }
public void testOverriddenUDLOperatorIntCall_527954() throws Exception {
makeAssertions();
}
// int operator""int(long double) { //$functionDeclaration
// return -1;
// }
// int main() { //$functionDeclaration
// auto k = 1.3int; //$localVariableDeclaration,c_default
// }
public void testUDLOperatorIntCall_527954() throws Exception {
Set<String> ignoredHighlightings = new HashSet<>();
ignoredHighlightings.add(SemanticHighlightings.OVERLOADED_OPERATOR);
makeAssertions(ignoredHighlightings);
}
}

View file

@ -56,6 +56,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@ -1809,7 +1810,36 @@ public class SemanticHighlightings {
|| token.getNode() instanceof ICPPASTClassVirtSpecifier;
}
}
/**
* Semantic highlighting for context-sensitive UDL like operator""if(...).
*
* This does not get its own color and style; rather, it uses
* the color and style of the 'Default' syntactic highlighting.
*/
private static final class ContextSensitiveUDLHighlighting extends SemanticHighlighting {
@Override
public String getPreferenceKey() {
return ICColorConstants.C_DEFAULT;
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
public boolean requiresImplicitNames() {
return true;
}
@Override
public boolean consumes(ISemanticToken token) {
IASTNode node = token.getNode();
return node instanceof IASTImplicitName && node.getParent() instanceof ICPPASTLiteralExpression;
}
}
private static boolean heuristicallyResolvesToEnumeration(ICPPUnknownBinding binding) {
IBinding[] resolved = HeuristicResolver.resolveUnknownBinding(binding);
return resolved.length == 1 && resolved[0] instanceof IEnumeration;
@ -1981,6 +2011,7 @@ public class SemanticHighlightings {
highlightings.put(new Key(230), new EnumeratorHighlighting());
highlightings.put(new Key(240), new ContextSensitiveKeywordHighlighting());
highlightings.put(new Key(250), new VariablePassedByNonconstRefHighlighting());
highlightings.put(new Key(260), new ContextSensitiveUDLHighlighting());
}
private static final String ExtensionPoint = "semanticHighlighting"; //$NON-NLS-1$