mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-09 09:15:38 +02:00
Fix for 178026: insert semi-colon when auto-inserting closing brace for class, union, struct and enum
This commit is contained in:
parent
d09020f2e4
commit
92a86b658e
5 changed files with 278 additions and 88 deletions
|
@ -65,6 +65,18 @@ public class CAutoIndentTest extends TestCase {
|
||||||
return (IAutoEditStrategy)fStrategyMap.get(contentType);
|
return (IAutoEditStrategy)fStrategyMap.get(contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empties the document, and returns the caret to the origin (0,0)
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
try {
|
||||||
|
goTo(0,0);
|
||||||
|
fDoc.set("");
|
||||||
|
} catch(BadLocationException ble) {
|
||||||
|
fail(ble.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void type(String text) throws BadLocationException {
|
public void type(String text) throws BadLocationException {
|
||||||
for (int i = 0; i < text.length(); ++i) {
|
for (int i = 0; i < text.length(); ++i) {
|
||||||
type(text.charAt(i));
|
type(text.charAt(i));
|
||||||
|
@ -396,4 +408,84 @@ public class CAutoIndentTest extends TestCase {
|
||||||
assertEquals("\t// int f;", tester.getLine(0)); //$NON-NLS-1$
|
assertEquals("\t// int f;", tester.getLine(0)); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests brackets with semi-colons are inserted in the appropriate
|
||||||
|
* contexts
|
||||||
|
* @throws BadLocationException
|
||||||
|
*/
|
||||||
|
public void testBracketWithSemiColonInsertion() throws BadLocationException {
|
||||||
|
AutoEditTester tester = createAutoEditTester();
|
||||||
|
String[] kw= new String[] {"class", "union", "struct", "enum"};
|
||||||
|
String[] kw_inh= new String[] {"class", "union", "struct", "enum"};
|
||||||
|
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type(kw[i]+" A {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals(kw[i]+" A {\n\t\r\n};", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$
|
||||||
|
tester.goTo(2,0);
|
||||||
|
tester.type(kw[i]+" A {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("\n// foo\n"+kw[i]+" A {\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// this tests for a sensible behaviour for enums, although the
|
||||||
|
// code generated is invalid, its the user entered part that is
|
||||||
|
// the problem
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type("\n\n\n"+kw[i]+" A\n:\npublic B\n,\npublic C\n{\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("\n\n\n"+kw[i]+" A\n:\n\tpublic B\n\t,\n\tpublic C\n\t{\n\t\n\t};", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<kw.length; i++) {
|
||||||
|
tester.reset();
|
||||||
|
|
||||||
|
tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$
|
||||||
|
tester.goTo(2,0);
|
||||||
|
tester.type(kw[i]+" /* for(int i=0; i<100; i++) {} */\nA \n{\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("\n// foo\n"+kw[i]+" /* for(int i=0; i<100; i++) {} */\nA \n{\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that brackets are inserted (without semi-colons) in appropriate
|
||||||
|
* contexts
|
||||||
|
* @throws BadLocationException
|
||||||
|
*/
|
||||||
|
public void testBracketInsertion() throws BadLocationException {
|
||||||
|
AutoEditTester tester = createAutoEditTester();
|
||||||
|
|
||||||
|
tester.type("for (;;) {\n");
|
||||||
|
assertEquals("for (;;) {\n\t\r\n}", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
|
||||||
|
tester.reset();
|
||||||
|
tester.type("for /*class*/ (;;) {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("for /*class*/ (;;) {\n\t\r\n}", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
|
||||||
|
tester.reset();
|
||||||
|
tester.type("for (;;) /*class*/ {\n"); //$NON-NLS-1$
|
||||||
|
assertEquals("for (;;) /*class*/ {\n\t\r\n}", tester.fDoc.get()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -684,71 +684,6 @@ public class CHeuristicScannerTest extends TestCase {
|
||||||
Assert.assertEquals(" ", indent);
|
Assert.assertEquals(" ", indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAnonymousIndentation1() {
|
|
||||||
fDocument.set( " MenuItem mi= new MenuItem(\"About...\");\n" +
|
|
||||||
" mi->addActionListener(\n" +
|
|
||||||
" new ActionListener() {\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAnonymousIndentation2() {
|
|
||||||
fDocument.set( " MenuItem mi= new MenuItem(\"About...\");\n" +
|
|
||||||
" mi->addActionListener(\n" +
|
|
||||||
" new ActionListener() {\n" +
|
|
||||||
" public void actionPerformed(ActionEvent event) {\n" +
|
|
||||||
" about();\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
");"
|
|
||||||
);
|
|
||||||
|
|
||||||
// this is bogus, since this is really just an unfinished call argument list - how could we know
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength() - 2).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testExceptionIndentation1() {
|
|
||||||
fDocument.set("public void processChildren(CompositeExpression result, IConfigurationElement element) throws CoreException {\n" +
|
|
||||||
" IConfigurationElement[] children= element.getChildren();\n" +
|
|
||||||
" if (children != null) {\n" +
|
|
||||||
" for (int i= 0; i < children.length; i++) {\n" +
|
|
||||||
" Expression child= parse(children[i]);\n" +
|
|
||||||
" if (child == null)\n" +
|
|
||||||
" new Bla(new CoreExeption(new Status(IStatus.ERROR, JavaPlugin.getPluginId()");
|
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testExceptionIndentation2() {
|
|
||||||
fDocument.set("public void processChildren(CompositeExpression result, IConfigurationElement element) throws CoreException {\n" +
|
|
||||||
" IConfigurationElement[] children= element.getChildren();\n" +
|
|
||||||
" if (children != null) {\n" +
|
|
||||||
" for (int i= 0; i < children.length; i++) {\n" +
|
|
||||||
" Expression child= parse(children[i]);\n" +
|
|
||||||
" if (child == null)\n" +
|
|
||||||
" new Bla(new CoreExeption(new Status(IStatus.ERROR, JavaPlugin.getPluginId(),");
|
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testExceptionIndentation3() {
|
|
||||||
fDocument.set("public void processChildren(CompositeExpression result, IConfigurationElement element) throws CoreException {\n" +
|
|
||||||
" IConfigurationElement[] children= element.getChildren();\n" +
|
|
||||||
" if (children != null) {\n" +
|
|
||||||
" for (int i= 0; i < children.length; i++) {\n" +
|
|
||||||
" Expression child= parse(children[i]);\n" +
|
|
||||||
" if (child == null)\n" +
|
|
||||||
" new char[] { new CoreExeption(new Status(IStatus.ERROR, JavaPlugin.getPluginId(),");
|
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testListAlignmentMethodDeclaration() {
|
public void testListAlignmentMethodDeclaration() {
|
||||||
// parameter declaration - alignment with parenthesis
|
// parameter declaration - alignment with parenthesis
|
||||||
fDocument.set( "\tvoid proc ( int par1, int par2,\n" +
|
fDocument.set( "\tvoid proc ( int par1, int par2,\n" +
|
||||||
|
@ -801,25 +736,13 @@ public class CHeuristicScannerTest extends TestCase {
|
||||||
fDocument.set(
|
fDocument.set(
|
||||||
" switch (i) {\n" +
|
" switch (i) {\n" +
|
||||||
" case 1:\n" +
|
" case 1:\n" +
|
||||||
" new Runnable() {\n" +
|
" do {\n" +
|
||||||
"");
|
"");
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
String indent= fScanner.computeIndentation(fDocument.getLength()).toString();
|
||||||
Assert.assertEquals(" ", indent);
|
Assert.assertEquals(" ", indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAnonymousTypeBraceNextLine() throws Exception {
|
|
||||||
fDocument.set(
|
|
||||||
" MenuItem mi= new MenuItem(\"About...\");\n" +
|
|
||||||
" mi->addActionListener(new ActionListener() " +
|
|
||||||
" {\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
String indent= fScanner.computeIndentation(fDocument.getLength() - 2).toString();
|
|
||||||
Assert.assertEquals(" ", indent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testClassInstanceCreationHeuristic() throws Exception {
|
public void testClassInstanceCreationHeuristic() throws Exception {
|
||||||
fDocument.set(" method(new std::vector<std::string>(10), foo, new int[])");
|
fDocument.set(" method(new std::vector<std::string>(10), foo, new int[])");
|
||||||
|
|
||||||
|
@ -841,6 +764,46 @@ public class CHeuristicScannerTest extends TestCase {
|
||||||
assertFalse(fHeuristicScanner.looksLikeClassInstanceCreationBackward(offset, CHeuristicScanner.UNBOUND));
|
assertFalse(fHeuristicScanner.looksLikeClassInstanceCreationBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFieldReferenceHeuristic() throws Exception {
|
||||||
|
fDocument.set("t.f=tp->f-T::f;");
|
||||||
|
for (int offset= 0; offset < 2; offset++)
|
||||||
|
assertFalse(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 2; offset < 4; offset++)
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 4; offset < 8; offset++)
|
||||||
|
assertFalse(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 8; offset < 10; offset++)
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 10; offset < 13; offset++)
|
||||||
|
assertFalse(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 13; offset < 14; offset++)
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
for (int offset= 15; offset < 15; offset++)
|
||||||
|
assertFalse(fHeuristicScanner.looksLikeFieldReferenceBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCompositeTypeDefinitionHeuristic() throws Exception {
|
||||||
|
int offset;
|
||||||
|
fDocument.set("class A {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
fDocument.set("class A : B {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
fDocument.set("struct A : B {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
fDocument.set("class A : virtual public B {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
fDocument.set("class A : public B, protected virtual C {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
fDocument.set("template <class T> class A : public B<int,float>, protected C<T> {");
|
||||||
|
offset= fDocument.get().indexOf("{");
|
||||||
|
assertTrue(fHeuristicScanner.looksLikeCompositeTypeDefinitionBackward(offset, CHeuristicScanner.UNBOUND));
|
||||||
|
}
|
||||||
|
|
||||||
public void testShiftOperator() throws Exception {
|
public void testShiftOperator() throws Exception {
|
||||||
fDocument.set(
|
fDocument.set(
|
||||||
" for (int j = 0; j == 0; j ++) {\n" +
|
" for (int j = 0; j == 0; j ++) {\n" +
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2000, 2006 IBM Corporation and others.
|
* Copyright (c) 2000, 2007 IBM Corporation and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -303,6 +303,13 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
|
||||||
if (reference != null)
|
if (reference != null)
|
||||||
buf.append(reference);
|
buf.append(reference);
|
||||||
buf.append('}');
|
buf.append('}');
|
||||||
|
int bound= c.offset > 200 ? c.offset - 200 : CHeuristicScanner.UNBOUND;
|
||||||
|
int bracePos = scanner.findOpeningPeer(c.offset - 1, bound, '{', '}');
|
||||||
|
if (bracePos != CHeuristicScanner.NOT_FOUND) {
|
||||||
|
if (scanner.looksLikeCompositeTypeDefinitionBackward(bracePos, bound)) {
|
||||||
|
buf.append(';');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// insert extra line upon new line between two braces
|
// insert extra line upon new line between two braces
|
||||||
else if (c.offset > start && contentStart < lineEnd && d.getChar(contentStart) == '}') {
|
else if (c.offset > start && contentStart < lineEnd && d.getChar(contentStart) == '}') {
|
||||||
|
|
|
@ -479,6 +479,8 @@ public final class CHeuristicScanner implements Symbols {
|
||||||
return TokenCLASS;
|
return TokenCLASS;
|
||||||
if ("while".equals(s)) //$NON-NLS-1$
|
if ("while".equals(s)) //$NON-NLS-1$
|
||||||
return TokenWHILE;
|
return TokenWHILE;
|
||||||
|
if ("union".equals(s)) //$NON-NLS-1$
|
||||||
|
return TokenUNION;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if ("delete".equals(s)) //$NON-NLS-1$
|
if ("delete".equals(s)) //$NON-NLS-1$
|
||||||
|
@ -499,6 +501,8 @@ public final class CHeuristicScanner implements Symbols {
|
||||||
return TokenDEFAULT;
|
return TokenDEFAULT;
|
||||||
if ("private".equals(s)) //$NON-NLS-1$
|
if ("private".equals(s)) //$NON-NLS-1$
|
||||||
return TokenPRIVATE;
|
return TokenPRIVATE;
|
||||||
|
if ("virtual".equals(s)) //$NON-NLS-1$
|
||||||
|
return TokenVIRTUAL;
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
if ("protected".equals(s)) //$NON-NLS-1$
|
if ("protected".equals(s)) //$NON-NLS-1$
|
||||||
|
@ -867,17 +871,17 @@ public final class CHeuristicScanner implements Symbols {
|
||||||
* <code>true</code> if <code>start</code> is at the following positions (|):
|
* <code>true</code> if <code>start</code> is at the following positions (|):
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* new new std::vector<std::string>|(10)
|
* new std::vector<std::string>|(10)
|
||||||
* new new str_vector |(10)
|
* new str_vector |(10)
|
||||||
* new new / * comment * / str_vector |(10)
|
* new / * comment * / str_vector |(10)
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* but not the following:
|
* but not the following:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* new new std::vector<std::string>(10)|
|
* new std::vector<std::string>(10)|
|
||||||
* new new std::vector<std::string>|(10)
|
* new std::vector<std::string>|(10)
|
||||||
* new new vector (10)|
|
* new vector (10)|
|
||||||
* vector |(10)
|
* vector |(10)
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -907,8 +911,8 @@ public final class CHeuristicScanner implements Symbols {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> if the document, when scanned backwards from <code>start</code>
|
* Returns <code>true</code> if the document, when scanned backwards from <code>start</code>
|
||||||
* appears to contain a field reference, i.e. a (optional) name preceded by a <code>.</code> or <code>-></code>
|
* appears to contain a field reference, i.e. a (optional) name preceded by a <code>.</code>
|
||||||
* The <code>start</code> must be before the operator.
|
* or <code>-></code> or <code>::</code>.
|
||||||
*
|
*
|
||||||
* @param start the position after the field reference operator.
|
* @param start the position after the field reference operator.
|
||||||
* @param bound the first position in <code>fDocument</code> to not consider any more, with
|
* @param bound the first position in <code>fDocument</code> to not consider any more, with
|
||||||
|
@ -928,7 +932,129 @@ public final class CHeuristicScanner implements Symbols {
|
||||||
if (token == Symbols.TokenMINUS) {
|
if (token == Symbols.TokenMINUS) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} else if (token == Symbols.TokenCOLON) {
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token == Symbols.TokenCOLON) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <code>true</code> if the document, when scanned backwards from <code>start</code>
|
||||||
|
* appears to be a composite type (class, struct, union) or enum definition. Examples:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* class A {
|
||||||
|
* struct A {
|
||||||
|
* class A : B {
|
||||||
|
* class A : virtual public B, protected C<T> {
|
||||||
|
* enum E {
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param start the position of the opening brace.
|
||||||
|
* @param bound the first position in <code>fDocument</code> to not consider any more, with
|
||||||
|
* <code>bound</code> < <code>start</code>, or <code>UNBOUND</code>
|
||||||
|
* @return <code>true</code> if the current position looks like a composite type definition
|
||||||
|
*/
|
||||||
|
public boolean looksLikeCompositeTypeDefinitionBackward(int start, int bound) {
|
||||||
|
int token= previousToken(start - 1, bound);
|
||||||
|
if (token == Symbols.TokenIDENT) {
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
switch (token) {
|
||||||
|
case Symbols.TokenCLASS:
|
||||||
|
case Symbols.TokenSTRUCT:
|
||||||
|
case Symbols.TokenUNION:
|
||||||
|
case Symbols.TokenENUM:
|
||||||
|
return true; // no base-clause
|
||||||
|
default:
|
||||||
|
// backtrack
|
||||||
|
token= previousToken(start - 1, bound);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// match base-clause
|
||||||
|
if (token == Symbols.TokenGREATERTHAN) {
|
||||||
|
findOpeningPeer(getPosition(), bound, '<', '>');
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token != Symbols.TokenLESSTHAN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
}
|
||||||
|
outer: while (token == Symbols.TokenIDENT) {// type name or base type
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
// match nested-name-specifier
|
||||||
|
while (token == Symbols.TokenCOLON) { // colon of qualification
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token != Symbols.TokenCOLON) { // second colon of qualification
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token != Symbols.TokenIDENT) // qualification name?
|
||||||
|
break;
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
}
|
||||||
|
switch (token) {
|
||||||
|
case Symbols.TokenVIRTUAL:
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
/* fallthrough */
|
||||||
|
case Symbols.TokenPUBLIC:
|
||||||
|
case Symbols.TokenPROTECTED:
|
||||||
|
case Symbols.TokenPRIVATE:
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token == Symbols.TokenVIRTUAL) {
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
}
|
||||||
|
if (token == Symbols.TokenCOMMA) {
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token == Symbols.TokenGREATERTHAN) {
|
||||||
|
findOpeningPeer(getPosition(), bound, '<', '>');
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token != Symbols.TokenLESSTHAN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
}
|
||||||
|
continue; // another base type
|
||||||
|
}
|
||||||
|
if (token != Symbols.TokenCOLON) // colon after class def identifier
|
||||||
|
return false;
|
||||||
|
/* fallthrough */
|
||||||
|
case Symbols.TokenCOLON:
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
break outer;
|
||||||
|
case Symbols.TokenCOMMA:
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token == Symbols.TokenGREATERTHAN) {
|
||||||
|
findOpeningPeer(getPosition(), bound, '<', '>');
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
if (token != Symbols.TokenLESSTHAN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
}
|
||||||
|
continue; // another base type
|
||||||
|
case Symbols.TokenIDENT:
|
||||||
|
break outer;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token != Symbols.TokenIDENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token= previousToken(getPosition(), bound);
|
||||||
|
switch (token) {
|
||||||
|
case Symbols.TokenCLASS:
|
||||||
|
case Symbols.TokenSTRUCT:
|
||||||
|
case Symbols.TokenUNION:
|
||||||
|
case Symbols.TokenENUM: // enum is actually not valid here
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ public interface Symbols {
|
||||||
int TokenDELETE= 1027;
|
int TokenDELETE= 1027;
|
||||||
int TokenCLASS= 1028;
|
int TokenCLASS= 1028;
|
||||||
int TokenSTRUCT= 1029;
|
int TokenSTRUCT= 1029;
|
||||||
int TokenENUM= 1030;
|
int TokenUNION= 1030;
|
||||||
|
int TokenENUM= 1031;
|
||||||
|
int TokenVIRTUAL= 1032;
|
||||||
int TokenIDENT= 2000;
|
int TokenIDENT= 2000;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue