diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index eaab8a61819..2eca9e19471 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -18,6 +18,7 @@ import junit.framework.TestSuite; import org.eclipse.cdt.core.dom.ast.ASTSignatureUtil; import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; +import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; @@ -28,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTDoStatement; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; @@ -98,6 +100,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; +import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.c.CFunction; @@ -5292,4 +5295,138 @@ public class AST2Tests extends AST2BaseTest { parseAndCheckBindings(getAboveComment(), ParserLanguage.C, true); parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true); } + + // #define IF if + // #define IF_P if ( + // #define IF_P_T if (1 + // #define SEMI_IF ; if + // #define IF_COND if (1) + // void test() { + public void testLeadingSyntax_Bug250251() throws Exception { + String code= getAboveComment(); + + IASTTranslationUnit tu= parseAndCheckBindings(code + "if (1) {};}"); + IASTFunctionDefinition f= getDeclaration(tu, 0); + IASTIfStatement i = getStatement(f, 0); + IASTExpression x= i.getConditionExpression(); + IToken syntax= x.getLeadingSyntax(); + checkToken(syntax, "if", -4); syntax= syntax.getNext(); + checkToken(syntax, "(", -1); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "if( 1) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + syntax= x.getLeadingSyntax(); + checkToken(syntax, "if", -5); syntax= syntax.getNext(); + checkToken(syntax, "(", -3); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "if(1) ; else ;}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); IASTStatement est= i.getElseClause(); + syntax= est.getLeadingSyntax(); + checkToken(syntax, "else", -5); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "IF(1) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + syntax= x.getLeadingSyntax(); + checkToken(syntax, "IF", -3); syntax= syntax.getNext(); + checkToken(syntax, "(", -1); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "IF_P 1) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + syntax= x.getLeadingSyntax(); + checkToken(syntax, "IF_P", -5); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "IF_P_T ) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + try { + syntax= x.getLeadingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + + tu= parseAndCheckBindings(code + "SEMI_IF (1) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 1); x= i.getConditionExpression(); + try { + syntax= x.getLeadingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + + tu= parseAndCheckBindings(code + "IF_COND {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + try { + syntax= x.getLeadingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + } + + // #define P(x) ) + // #define BLOCK() {} + // #define T_P 1) + // #define P_BLOCK ){} + // #define IF_COND if (1) + // void test() { + public void testTrailingSyntax_Bug250251() throws Exception { + String code= getAboveComment(); + + IASTTranslationUnit tu= parseAndCheckBindings(code + "if (1) {};}"); + IASTFunctionDefinition f= getDeclaration(tu, 0); + IASTIfStatement i = getStatement(f, 0); + IASTExpression x= i.getConditionExpression(); + IToken syntax= x.getTrailingSyntax(); + checkToken(syntax, ")", 0); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "do {} while(1 );}"); + f= getDeclaration(tu, 0); IASTDoStatement dstmt= getStatement(f, 0); x= dstmt.getCondition(); + syntax= x.getTrailingSyntax(); + checkToken(syntax, ")", 1); syntax= syntax.getNext(); + checkToken(syntax, ";", 2); syntax= syntax.getNext(); + assertNull(syntax); + + + tu= parseAndCheckBindings(code + "if(1 ) BLOCK()}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + syntax= x.getTrailingSyntax(); + checkToken(syntax, ")", 1); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "if(1 P(0) {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + syntax= x.getTrailingSyntax(); + checkToken(syntax, "P", 1); syntax= syntax.getNext(); + checkToken(syntax, "(", 2); syntax= syntax.getNext(); + checkToken(syntax, "0", 3); syntax= syntax.getNext(); + checkToken(syntax, ")", 4); syntax= syntax.getNext(); + assertNull(syntax); + + tu= parseAndCheckBindings(code + "if (T_P {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + try { + syntax= x.getTrailingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + + tu= parseAndCheckBindings(code + "if (1 P_BLOCK }"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + try { + syntax= x.getTrailingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + + tu= parseAndCheckBindings(code + "IF_COND {}}"); + f= getDeclaration(tu, 0); i= getStatement(f, 0); x= i.getConditionExpression(); + try { + syntax= x.getTrailingSyntax(); + fail(); + } catch (ExpansionOverlapsBoundaryException e) {} + } + + private void checkToken(IToken token, String image, int offset) { + assertEquals(image, token.getImage()); + assertEquals(offset, token.getOffset()); + assertEquals(image.length(), token.getLength()); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java index f37ba6b952e..ef05190e6ec 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java @@ -49,6 +49,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; import org.eclipse.cdt.internal.core.parser.scanner.ILocationCtx; import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo; import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; +import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; public class LocationMapTests extends BaseTestCase { public class Loc implements IASTFileLocation { @@ -102,7 +103,7 @@ public class LocationMapTests extends BaseTestCase { @Override protected void setUp() throws Exception { super.setUp(); - fLocationMap= new LocationMap(); + fLocationMap= new LocationMap(new LexerOptions()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTVisitor.java index e7169378a9f..50b2be9df4d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTVisitor.java @@ -116,6 +116,38 @@ public abstract class ASTVisitor { */ public boolean shouldVisitTemplateParameters = false; + /** + * Creates a visitor that does not visit any kind of node per default. + */ + public ASTVisitor() { + this(false); + } + + /** + * Creates a visitor. + * @param visitNodes whether visitor is setup to visit all nodes per default. + * @since 5.1 + */ + public ASTVisitor(boolean visitNodes) { + shouldVisitArrayModifiers= visitNodes; + shouldVisitBaseSpecifiers= visitNodes; + shouldVisitDeclarations= visitNodes; + shouldVisitDeclarators= visitNodes; + shouldVisitDeclSpecifiers= visitNodes; + shouldVisitDesignators= visitNodes; + shouldVisitEnumerators= visitNodes; + shouldVisitExpressions= visitNodes; + shouldVisitInitializers= visitNodes; + shouldVisitNames= visitNodes; + shouldVisitNamespaces= visitNodes; + shouldVisitParameterDeclarations= visitNodes; + shouldVisitProblems= visitNodes; + shouldVisitStatements= visitNodes; + shouldVisitTemplateParameters= visitNodes; + shouldVisitTranslationUnit= visitNodes; + shouldVisitTypeIds= visitNodes; + } + // visit methods public int visit(IASTTranslationUnit tu) { return PROCESS_CONTINUE; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ExpansionOverlapsBoundaryException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ExpansionOverlapsBoundaryException.java new file mode 100644 index 00000000000..0a67d582abf --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ExpansionOverlapsBoundaryException.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.dom.ast; + +/** + * See {@link IASTNode#getTrailingSyntax()} and {@link IASTNode#getLeadingSyntax()}. + * @since 5.1 + */ +public class ExpansionOverlapsBoundaryException extends Exception { + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNode.java index 0e6d288390d..9bb7216d81c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNode.java @@ -6,16 +6,18 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * Doug Schaefer - Initial API and implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; +import org.eclipse.cdt.core.parser.IToken; + /** * This is the root node in the physical AST. A physical node represents a chunk * of text in the source program. * - * @author Doug Schaefer + * @noimplement This interface is not intended to be implemented by clients. */ public interface IASTNode { @@ -128,4 +130,48 @@ public interface IASTNode { * @since 4.0 */ public boolean contains(IASTNode node); + + /** + * Returns the tokens that can be found between this node and its left sibling (or the + * beginning of the parent, if there is no left sibling). The tokens are obtained + * from the lexer, no preprocessing is performed. + * The offsets of the tokens are relative to the file-offset of this node. + *
Examples looking at the condition of if-statements: + *
+ * #define IF if + * #define IF_P if ( + * #define IF_P_T if (true + * #define SEMI_IF ; if + * #define IF_COND if (true) + * void test() { + * if (true) {} // leading syntax: 'if (' + * IF (true) {} // leading syntax: 'IF (' + * IF_P true) {} // leading syntax: 'IF_P' + * IF_P_T ) {} // throws ExpansionOverlapsBoundaryException + * SEMI_IF (true) {} // throws ExpansionOverlapsBoundaryException + * IF_COND // throws ExpansionOverlapsBoundaryException + *+ * @return a chain of tokens or
null
, if there are none.
+ * @throws ExpansionOverlapsBoundaryException if one of the boundaries of the leading syntax is
+ * overlapped by a macro-expansion.
+ * @throws UnsupportedOperationException if invoked on preprocessor nodes, or nodes that are not
+ * part of a translation unit.
+ * @since 5.1
+ */
+ public IToken getLeadingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException;
+
+ /**
+ * Returns the tokens that can be found between this node and its right sibling (or the
+ * end of the parent, if there is no right sibling). The tokens are obtained from the lexer,
+ * no preprocessing is performed.
+ * The offsets of the tokens are relative to the file-offset of the end of this node.
+ * For examples see {@link #getLeadingSyntax()}.
+ * @return a chain of tokens or null
, if there are none.
+ * @throws ExpansionOverlapsBoundaryException if one of the boundaries of the trailing syntax is
+ * overlapped by a macro-expansion.
+ * @throws UnsupportedOperationException if invoked on preprocessor nodes, or nodes that are not
+ * part of a translation unit.
+ * @since 5.1
+ */
+ public IToken getTrailingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNode.java
index 5b1e725b34b..538bfe82fa8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNode.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNode.java
@@ -1,27 +1,34 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * IBM Rational Software - Initial API and implementation
+ * John Camelon - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.parser.IToken;
+import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
+import org.eclipse.cdt.internal.core.parser.scanner.ILexerLog;
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
+import org.eclipse.cdt.internal.core.parser.scanner.Lexer;
+import org.eclipse.cdt.internal.core.parser.scanner.Token;
+import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
/**
- * @author jcamelon
+ * Base class for all non-preprocessor nodes in the AST.
*/
public abstract class ASTNode implements IASTNode {
@@ -182,4 +189,98 @@ public abstract class ASTNode implements IASTNode {
}
return false;
}
+
+ public IToken getLeadingSyntax() throws ExpansionOverlapsBoundaryException {
+ int left= getBoundary(-1);
+ return getSyntax(left, offset, -1);
+ }
+
+ public IToken getTrailingSyntax() throws ExpansionOverlapsBoundaryException {
+ int right= getBoundary(1);
+ return getSyntax(offset+length, right, 1);
+ }
+
+ /**
+ * Compute the sequence number of the boundary of the leading/trailing syntax.
+ */
+ private int getBoundary(int direction) {
+ ASTNodeSearch visitor= new ASTNodeSearch(this);
+ IASTNode sib= direction < 0 ? visitor.findLeftSibling() : visitor.findRightSibling();
+ if (sib == null) {
+ direction= -direction;
+ sib= getParent();
+ }
+ if (sib instanceof ASTNode) {
+ ASTNode astNode= (ASTNode) sib;
+ int offset= astNode.getOffset();
+ if (direction < 0) {
+ offset+= astNode.getLength();
+ }
+ return offset;
+ }
+ // no parent
+ throw new UnsupportedOperationException();
+ }
+
+
+ private IToken getSyntax(int fromSequenceNumber, int nextSequenceNumber, int direction) throws ExpansionOverlapsBoundaryException {
+ final IASTTranslationUnit tu= getTranslationUnit();
+ if (!(tu instanceof ASTNode))
+ throw new UnsupportedOperationException();
+
+ ILocationResolver lr= (ILocationResolver) tu.getAdapter(ILocationResolver.class);
+ if (lr == null)
+ throw new UnsupportedOperationException();
+
+ int endSequenceNumber= lr.convertToSequenceEndNumber(nextSequenceNumber);
+ IASTFileLocation total= lr.getMappedFileLocation(fromSequenceNumber, endSequenceNumber-fromSequenceNumber);
+ IASTFileLocation myfloc= getFileLocation();
+ if (total == null || myfloc == null)
+ throw new UnsupportedOperationException();
+
+ if (!total.getFileName().equals(myfloc.getFileName()))
+ throw new ExpansionOverlapsBoundaryException();
+
+ if (fromSequenceNumber > 0) {
+ IASTFileLocation fl= lr.getMappedFileLocation(fromSequenceNumber-1, endSequenceNumber-fromSequenceNumber+1);
+ if (fl.getFileName().equals(total.getFileName()) && fl.getNodeOffset() == total.getNodeOffset())
+ throw new ExpansionOverlapsBoundaryException();
+ }
+
+ if (endSequenceNumber < ((ASTNode) tu).getOffset() + ((ASTNode) tu).getLength()) {
+ IASTFileLocation fl= lr.getMappedFileLocation(fromSequenceNumber, nextSequenceNumber-fromSequenceNumber+1);
+ if (fl.getFileName().equals(total.getFileName()) && fl.getNodeLength() == total.getNodeLength())
+ throw new ExpansionOverlapsBoundaryException();
+ }
+
+ int adjustment= total.getNodeOffset() - myfloc.getNodeOffset();
+ if (direction > 0) {
+ adjustment-= myfloc.getNodeLength();
+ }
+
+ char[] txt= lr.getUnpreprocessedSignature(total);
+ Lexer lex= new Lexer(txt, (LexerOptions) tu.getAdapter(LexerOptions.class), ILexerLog.NULL, null);
+ try {
+ Token result= lex.nextToken();
+ if (result.getType() == IToken.tEND_OF_INPUT)
+ return null;
+
+ Token last= result;
+ for(;;) {
+ int offset= last.getOffset() + adjustment;
+ int endOffset= last.getEndOffset() + adjustment;
+ last.setOffset(offset, endOffset);
+
+ Token t= lex.nextToken();
+ if (t.getType() == IToken.tEND_OF_INPUT)
+ break;
+ last.setNext(t);
+ last= t;
+ }
+ return result;
+ } catch (OffsetLimitReachedException e) {
+ // does not happen without using content assist limit
+ }
+ return null;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSearch.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSearch.java
new file mode 100644
index 00000000000..8886da416cf
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSearch.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Markus Schorn - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.dom.parser;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTProblem;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
+import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator;
+import org.eclipse.cdt.core.dom.ast.c.ICASTVisitor;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisitor;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
+
+/**
+ * Utility class to search for siblings of an ast node
+ */
+public class ASTNodeSearch extends ASTVisitor implements ICASTVisitor, ICPPASTVisitor {
+ private static final int LEFT = 0;
+ private static final int RIGHT= 1;
+ private int fMode;
+ private IASTNode fLeft;
+ private IASTNode fRight;
+ private final IASTNode fNode;
+ private final IASTNode fParent;
+
+ public ASTNodeSearch(IASTNode node) {
+ super(true);
+ fNode= node;
+ fParent= node.getParent();
+ }
+
+ public IASTNode findLeftSibling() {
+ if (fParent == null)
+ return null;
+
+ fMode= LEFT;
+ fLeft= fRight= null;
+ fParent.accept(this);
+ return fLeft;
+ }
+
+ public IASTNode findRightSibling() {
+ if (fParent == null)
+ return null;
+
+ fMode= RIGHT;
+ fLeft= fRight= null;
+ fParent.accept(this);
+ return fRight;
+ }
+
+ private int process(IASTNode node) {
+ if (node == fParent)
+ return PROCESS_CONTINUE;
+
+ switch(fMode) {
+ case LEFT:
+ if (node == fNode)
+ return PROCESS_ABORT;
+ fLeft= node;
+ return PROCESS_SKIP;
+ case RIGHT:
+ if (node == fNode) {
+ fLeft= fNode;
+ } else if (fLeft != null) {
+ fRight= node;
+ return PROCESS_ABORT;
+ }
+ return PROCESS_SKIP;
+ }
+ return PROCESS_SKIP;
+ }
+
+
+ public int visit(ICASTDesignator designator) {
+ return process(designator);
+ }
+
+ @Override
+ public int visit(IASTArrayModifier arrayModifier) {
+ return process(arrayModifier);
+ }
+
+ @Override
+ public int visit(IASTDeclaration declaration) {
+ return process(declaration);
+ }
+
+ @Override
+ public int visit(IASTDeclarator declarator) {
+ return process(declarator);
+ }
+
+ @Override
+ public int visit(IASTDeclSpecifier declSpec) {
+ return process(declSpec);
+ }
+
+ @Override
+ public int visit(IASTEnumerator enumerator) {
+ return process(enumerator);
+ }
+
+ @Override
+ public int visit(IASTExpression expression) {
+ return process(expression);
+ }
+
+ @Override
+ public int visit(IASTInitializer initializer) {
+ return process(initializer);
+ }
+
+ @Override
+ public int visit(IASTName name) {
+ return process(name);
+ }
+
+ @Override
+ public int visit(IASTParameterDeclaration parameterDeclaration) {
+ return process(parameterDeclaration);
+ }
+
+ @Override
+ public int visit(IASTProblem problem) {
+ return process(problem);
+ }
+
+ @Override
+ public int visit(IASTStatement statement) {
+ return process(statement);
+ }
+
+ @Override
+ public int visit(IASTTranslationUnit tu) {
+ return process(tu);
+ }
+
+ @Override
+ public int visit(IASTTypeId typeId) {
+ return process(typeId);
+ }
+
+ public int visit(ICPPASTBaseSpecifier baseSpecifier) {
+ return process(baseSpecifier);
+ }
+
+ public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
+ return process(namespaceDefinition);
+ }
+
+ public int visit(ICPPASTTemplateParameter templateParameter) {
+ return process(templateParameter);
+ }
+
+ public int leave(ICASTDesignator designator) {
+ return PROCESS_CONTINUE;
+ }
+ public int leave(ICPPASTBaseSpecifier baseSpecifier) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int leave(ICPPASTNamespaceDefinition namespaceDefinition) {
+ return PROCESS_CONTINUE;
+ }
+
+ public int leave(ICPPASTTemplateParameter templateParameter) {
+ return PROCESS_CONTINUE;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
index 53498f3ac58..44ee8087166 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
@@ -37,6 +37,7 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
import org.eclipse.cdt.internal.core.parser.scanner.ISkippedIndexedFilesListener;
import org.eclipse.cdt.internal.core.parser.scanner.IncludeFileContent;
+import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
import org.eclipse.core.runtime.CoreException;
/**
@@ -294,6 +295,9 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
if (adapter.isAssignableFrom(IIndexFileSet.class)) {
return fIndexFileSet;
}
+ if (adapter.isAssignableFrom(LexerOptions.class)) {
+ return fLocationResolver.getLexerOptions();
+ }
return null;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTLiteralNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTLiteralNode.java
index 753a2515baf..2663056893a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTLiteralNode.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTLiteralNode.java
@@ -16,6 +16,7 @@ import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriterVisitor;
/**
@@ -78,4 +79,12 @@ public class ASTLiteralNode implements IASTNode {
public void setPropertyInParent(ASTNodeProperty property) {
}
+
+ public IToken getLeadingSyntax() {
+ throw new UnsupportedOperationException();
+ }
+
+ public IToken getTrailingSyntax() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
index e62f74a19c5..3a3382e75c9 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
@@ -41,6 +41,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode;
+import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSpecification;
@@ -77,6 +78,16 @@ abstract class ASTPreprocessorNode extends ASTNode {
void findNode(ASTNodeSpecification> nodeSpec) {
nodeSpec.visit(this);
}
+
+ @Override
+ public IToken getLeadingSyntax() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IToken getTrailingSyntax() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
index 7ffea6ca118..448b484ed13 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
@@ -138,7 +138,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
// state information
private final CharArrayMap