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 ab4ab50e37b..d5c1d13ea53 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 @@ -10094,7 +10094,7 @@ public class AST2CPPTests extends AST2TestBase { assertInstance(sDefinition, ICPPASTCompositeTypeSpecifier.class); assertTrue(((ICPPASTCompositeTypeSpecifier)sDefinition).isFinal()); } - + // struct S { // template // void foo(T t) final { @@ -10134,6 +10134,16 @@ public class AST2CPPTests extends AST2TestBase { public void testFinalParameter() throws Exception { parseAndCheckBindings(); } + + // struct S __final {}; + // struct T { void foo() __final; }; + public void testFinalGccExtension_442457() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPClassType s = bh.assertNonProblem("S"); + assertTrue(s.isFinal()); + ICPPMethod foo = bh.assertNonProblem("foo"); + assertTrue(foo.isFinal()); + } // struct S1 {}; // S1 s1; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/AbstractCPPParserExtensionConfiguration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/AbstractCPPParserExtensionConfiguration.java index 07f3913ca02..8f7fe9ce6f8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/AbstractCPPParserExtensionConfiguration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/AbstractCPPParserExtensionConfiguration.java @@ -11,8 +11,13 @@ *******************************************************************************/ package org.eclipse.cdt.core.dom.parser.cpp; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider; import org.eclipse.cdt.core.parser.ParserLanguage; +import org.eclipse.cdt.core.parser.IToken.ContextSensitiveTokenType; import org.eclipse.cdt.internal.core.dom.parser.GCCBuiltinSymbolProvider; @@ -161,4 +166,12 @@ public abstract class AbstractCPPParserExtensionConfiguration implements ICPPPar public IBuiltinBindingsProvider getBuiltinBindingsProvider() { return new GCCBuiltinSymbolProvider(ParserLanguage.CPP, supportGCCOtherBuiltinSymbols()); } + + /** + * @since 5.9 + */ + @Override + public Map getAdditionalContextSensitiveKeywords() { + return Collections.emptyMap(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/GPPParserExtensionConfiguration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/GPPParserExtensionConfiguration.java index 23258d5da2b..d67fffb03b7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/GPPParserExtensionConfiguration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/GPPParserExtensionConfiguration.java @@ -12,8 +12,13 @@ *******************************************************************************/ package org.eclipse.cdt.core.dom.parser.cpp; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider; +import org.eclipse.cdt.core.parser.GCCKeywords; import org.eclipse.cdt.core.parser.ParserLanguage; +import org.eclipse.cdt.core.parser.IToken.ContextSensitiveTokenType; import org.eclipse.cdt.internal.core.dom.parser.GCCBuiltinSymbolProvider; /** @@ -131,4 +136,12 @@ public class GPPParserExtensionConfiguration extends AbstractCPPParserExtensionC public IBuiltinBindingsProvider getBuiltinBindingsProvider() { return new GCCBuiltinSymbolProvider(ParserLanguage.CPP, true); } + + @Override + public Map getAdditionalContextSensitiveKeywords() { + Map result = + new HashMap<>(super.getAdditionalContextSensitiveKeywords()); + result.put(GCCKeywords.__FINAL, ContextSensitiveTokenType.FINAL); + return result; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/ICPPParserExtensionConfiguration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/ICPPParserExtensionConfiguration.java index 53779093bb4..6be67d8b69f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/ICPPParserExtensionConfiguration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/ICPPParserExtensionConfiguration.java @@ -13,8 +13,11 @@ *******************************************************************************/ package org.eclipse.cdt.core.dom.parser.cpp; +import java.util.Map; + import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider; import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration; +import org.eclipse.cdt.core.parser.IToken.ContextSensitiveTokenType; /** * C++ parser extension configuration interface. @@ -146,6 +149,12 @@ public interface ICPPParserExtensionConfiguration { */ public boolean supportFunctionStyleAssembler(); + /** + * Additional variants of context-sensitive keywords. + * @since 5.9 + */ + public Map getAdditionalContextSensitiveKeywords(); + /** * @deprecated use {@link #getBuiltinBindingsProvider()} instead. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/GCCKeywords.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/GCCKeywords.java index e4bedec191d..9770db2f6b9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/GCCKeywords.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/GCCKeywords.java @@ -29,6 +29,8 @@ public class GCCKeywords { public static final String __INT128 = "__int128"; /** @since 5.5 */ public static final String __FLOAT128 = "__float128"; + /** @since 5.9 */ + public static final String __FINAL = "__final"; public static final char[] cpTYPEOF = TYPEOF.toCharArray(), @@ -84,4 +86,8 @@ public class GCCKeywords { public static final char[] cp__is_final= "__is_final".toCharArray(), cp__underlying_type= "__underlying_type".toCharArray(); + + /** @since 5.9 */ + public static final char[] + cp__FINAL= __FINAL.toCharArray(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java index 4917bf17d8f..f90daa171ca 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java @@ -216,6 +216,15 @@ public interface IToken { int FIRST_RESERVED_IExtensionToken = 243; int LAST_RESERVED_IExtensionToken = 299; + + /** + * Token types for context-sensitive tokens. + * @since 5.9 + */ + enum ContextSensitiveTokenType { + OVERRIDE, + FINAL + } /** diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java index d2097e47c99..52284de7bd2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java @@ -65,6 +65,8 @@ public class Keywords { public static final String EXPORT = "export"; public static final String EXTERN = "extern"; public static final String FALSE = "false"; + /** @since 5.9 */ + public static final String FINAL = "final"; public static final String FLOAT = "float"; public static final String FOR = "for"; public static final String FRIEND = "friend"; @@ -86,6 +88,8 @@ public class Keywords { public static final String OPERATOR = "operator"; public static final String OR = "or"; public static final String OR_EQ = "or_eq"; + /** @since 5.9 */ + public static final String OVERRIDE = "override"; public static final String PRIVATE = "private"; public static final String PROTECTED = "protected"; public static final String PUBLIC = "public"; @@ -169,7 +173,7 @@ public class Keywords { public static final char[] cFLOAT = "float".toCharArray(); public static final char[] cFOR = "for".toCharArray(); /** @since 5.5 */ - public static final char[] cFINAL = "final".toCharArray(); + public static final char[] cFINAL = FINAL.toCharArray(); public static final char[] cFRIEND = "friend".toCharArray(); public static final char[] cGOTO = "goto".toCharArray(); public static final char[] cIF = "if".toCharArray(); @@ -189,7 +193,7 @@ public class Keywords { public static final char[] cOR = "or".toCharArray(); public static final char[] cOR_EQ = "or_eq".toCharArray(); /** @since 5.5 */ - public static final char[] cOVERRIDE = "override".toCharArray(); + public static final char[] cOVERRIDE = OVERRIDE.toCharArray(); public static final char[] cPRIVATE = "private".toCharArray(); public static final char[] cPROTECTED = "protected".toCharArray(); public static final char[] cPUBLIC = "public".toCharArray(); 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 6377117b0e7..1edb957f6cc 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 @@ -19,9 +19,10 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; @@ -145,6 +146,7 @@ import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.IToken.ContextSensitiveTokenType; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.ParserMode; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -189,6 +191,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { private final ICPPNodeFactory nodeFactory; private TemplateIdStrategy fTemplateParameterListStrategy; + + private Map fContextSensitiveTokens; public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService log, ICPPParserExtensionConfiguration config) { @@ -215,8 +219,25 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { this.index= index; this.nodeFactory = CPPNodeFactory.getDefault(); scanner.setSplitShiftROperator(true); + fContextSensitiveTokens = createContextSensitiveTokenMap(config); } - + + private Map createContextSensitiveTokenMap( + ICPPParserExtensionConfiguration config) { + Map result = new HashMap(); + result.put(Keywords.OVERRIDE, ContextSensitiveTokenType.OVERRIDE); + result.put(Keywords.FINAL, ContextSensitiveTokenType.FINAL); + result.putAll(config.getAdditionalContextSensitiveKeywords()); + return result; + } + + private ContextSensitiveTokenType getContextSensitiveType(IToken token) { + if (!(token.getType() == IToken.tIDENTIFIER)) { + return null; + } + return fContextSensitiveTokens.get(new String(token.getCharImage())); + } + @Override protected IASTName identifier() throws EndOfFileException, BacktrackException { switch (LT(1)) { @@ -3640,16 +3661,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { throws EndOfFileException, BacktrackException { while (true) { IToken token = LAcatchEOF(1); - if (token.getType() != IToken.tIDENTIFIER) - break; - char[] tokenImage = token.getCharImage(); - if (Arrays.equals(Keywords.cOVERRIDE, tokenImage)) { + ContextSensitiveTokenType contextSensitiveType = getContextSensitiveType(token); + if (contextSensitiveType == ContextSensitiveTokenType.OVERRIDE) { consume(); ICPPASTVirtSpecifier spec = nodeFactory.newVirtSpecifier( ICPPASTVirtSpecifier.SpecifierKind.Override); setRange(spec, token.getOffset(), token.getOffset() + token.getLength()); typeRelevantDtor.addVirtSpecifier(spec); - } else if (Arrays.equals(Keywords.cFINAL, tokenImage)) { + } else if (contextSensitiveType == ContextSensitiveTokenType.FINAL) { consume(); ICPPASTVirtSpecifier spec = nodeFactory.newVirtSpecifier( ICPPASTVirtSpecifier.SpecifierKind.Final); @@ -4489,8 +4508,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { */ private void classVirtSpecifier(ICPPASTCompositeTypeSpecifier astClassSpecifier) throws EndOfFileException, BacktrackException { IToken token = LA(); - char[] tokenImage = token.getCharImage(); - if (token.getType() == IToken.tIDENTIFIER && Arrays.equals(Keywords.cFINAL, tokenImage)){ + ContextSensitiveTokenType contextSensitiveType = getContextSensitiveType(token); + if (contextSensitiveType == ContextSensitiveTokenType.FINAL) { consume(); ICPPASTClassVirtSpecifier spec = nodeFactory.newClassVirtSpecifier( ICPPASTClassVirtSpecifier.SpecifierKind.Final);