1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Information about syntax between ast-nodes, bug 250251.

This commit is contained in:
Markus Schorn 2008-10-14 09:29:23 +00:00
parent 10b2bb8da5
commit dd5413a3a2
18 changed files with 632 additions and 19 deletions

View file

@ -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());
}
}

View file

@ -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

View file

@ -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;

View file

@ -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 {
}

View file

@ -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.
* <p> <b>Examples</b> looking at the condition of if-statements:
* <pre>
* #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
* </pre>
* @return a chain of tokens or <code>null</code>, 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.
* <p> For examples see {@link #getLeadingSyntax()}.
* @return a chain of tokens or <code>null</code>, 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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -138,7 +138,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
// state information
private final CharArrayMap<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(512);
private final LocationMap fLocationMap = new LocationMap();
private final LocationMap fLocationMap;
/** Set of already included files */
private final HashSet<String> fAllIncludedFiles= new HashSet<String>();
@ -161,6 +161,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fLexOptions.fSupportAtSignInIdentifiers= configuration.supportAtSignInIdentifiers();
fLexOptions.fSupportMinAndMax = configuration.supportMinAndMaxOperators();
fLexOptions.fSupportSlashPercentComments= configuration.supportSlashPercentComments();
fLocationMap= new LocationMap(fLexOptions);
fKeywords= new CharArrayIntMap(40, -1);
fPPKeywords= new CharArrayIntMap(40, -1);
configureKeywords(language, configuration);

View file

@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree;
import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSpecification;
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
/**
@ -163,4 +164,16 @@ public interface ILocationResolver {
* @since 5.0
*/
IASTPreprocessorMacroExpansion[] getMacroExpansions(IASTFileLocation loc);
/**
* If you want to use the sequence number of an ast-node as the end of a previous node,
* it needs to be adjusted, because gaps are used for the encoding of directives.
* @return the adjusted sequence number, to be used as end-number
*/
int convertToSequenceEndNumber(int sequenceNumber);
/**
* Returns the lexer options that have been used by the preprocessor.
*/
LexerOptions getLexerOptions();
}

View file

@ -98,6 +98,14 @@ abstract class LocationCtx implements ILocationCtx {
return null;
}
public int convertToSequenceEndNumber(int sequenceNumber) {
// if the sequence number is the beginning of this context, skip the denotation of this
// context in the parent.
if (sequenceNumber == fSequenceNumber)
return sequenceNumber - fEndOffsetInParent + fOffsetInParent;
return sequenceNumber;
}
/**
* Returns the minimal file location containing the specified sequence number range, assuming
* that it is contained in this context.

View file

@ -109,6 +109,21 @@ class LocationCtxContainer extends LocationCtx {
return null;
}
@Override
public int convertToSequenceEndNumber(int sequenceNumber) {
// try to delegate to a child.
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
if (child != null)
sequenceNumber= child.convertToSequenceEndNumber(sequenceNumber);
// if the potentially converted sequence number is the beginning of this context,
// skip the denotation of this context in the parent.
if (sequenceNumber == fSequenceNumber)
return sequenceNumber - fEndOffsetInParent + fOffsetInParent;
return sequenceNumber;
}
@Override
public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child.

View file

@ -34,6 +34,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSpecification;
import org.eclipse.cdt.internal.core.dom.parser.ASTProblem;
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
/**
* Converts the offsets relative to various contexts to the global sequence number. Also creates and stores
@ -43,6 +44,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTProblem;
public class LocationMap implements ILocationResolver {
private static final IASTName[] EMPTY_NAMES = {};
private final LexerOptions fLexerOptions;
private String fTranslationUnitPath;
private IASTTranslationUnit fTranslationUnit;
@ -60,6 +62,14 @@ public class LocationMap implements ILocationResolver {
private IdentityHashMap<IBinding, IASTPreprocessorMacroDefinition> fMacroDefinitionMap= null;
private List<ISkippedIndexedFilesListener> fSkippedFilesListeners= new ArrayList<ISkippedIndexedFilesListener>();
public LocationMap(LexerOptions lexOptions) {
fLexerOptions= lexOptions;
}
public LexerOptions getLexerOptions() {
return fLexerOptions;
}
public void registerPredefinedMacro(IMacroBinding macro) {
registerPredefinedMacro(macro, null, -1);
}
@ -392,6 +402,10 @@ public class LocationMap implements ILocationResolver {
return fRootContext.findMappedFileLocation(sequenceNumber, length);
}
public int convertToSequenceEndNumber(int sequenceNumber) {
return fRootContext.convertToSequenceEndNumber(sequenceNumber);
}
public char[] getUnpreprocessedSignature(IASTFileLocation loc) {
ASTFileLocation floc= convertFileLocation(loc);
if (floc == null) {

View file

@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer;
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
import org.eclipse.jface.text.IRegion;
import org.eclipse.text.edits.ReplaceEdit;
@ -99,7 +100,8 @@ public class MultiMacroExpansionExplorer extends MacroExpansionExplorer {
fBoundaries[++bidx]= to;
fDelegates[++didx]= new SingleMacroExpansionExplorer(new String(fSource, from, to-from),
refs.toArray(new IASTName[refs.size()]), fMacroLocations,
fFilePath, refLoc.getStartingLineNumber(), isPPCond);
fFilePath, refLoc.getStartingLineNumber(), isPPCond,
(LexerOptions) tu.getAdapter(LexerOptions.class));
}
}
fBoundaries[++bidx]= fSource.length;

View file

@ -26,12 +26,6 @@ import org.eclipse.text.edits.ReplaceEdit;
* @since 5.0
*/
public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
private static final LexerOptions LEX_OPTIONS= new LexerOptions();
static {
LEX_OPTIONS.fCreateImageLocations= false;
}
private final String fInput;
private final CharArrayMap<PreprocessorMacro> fDictionary;
private MacroExpansionStep fFullExpansion;
@ -40,16 +34,19 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
private final int fLineNumber;
private final Map<IMacroBinding, IASTFileLocation> fMacroLocationMap;
private final boolean fIsPPCondition;
private final LexerOptions fLexerOptions;
public SingleMacroExpansionExplorer(String input, IASTName[] refs,
Map<IMacroBinding, IASTFileLocation> macroDefinitionLocationMap,
String filePath, int lineNumber, boolean isPPCondition) {
String filePath, int lineNumber, boolean isPPCondition, LexerOptions options) {
fInput= input;
fDictionary= createDictionary(refs);
fMacroLocationMap= macroDefinitionLocationMap;
fFilePath= filePath;
fLineNumber= lineNumber;
fIsPPCondition= isPPCondition;
fLexerOptions= (LexerOptions) options.clone();
fLexerOptions.fCreateImageLocations= false;
}
private CharArrayMap<PreprocessorMacro> createDictionary(IASTName[] refs) {
@ -80,7 +77,7 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
}
private void computeExpansion() {
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS);
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, fLexerOptions);
MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE);
expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition);
@ -96,7 +93,7 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
if (step < 0 || step >= fExpansionCount) {
throw new IndexOutOfBoundsException();
}
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS);
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, fLexerOptions);
MacroExpansionTracker tracker= new MacroExpansionTracker(step);
expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition);

View file

@ -15,6 +15,7 @@ import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException;
import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
@ -36,6 +37,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.core.runtime.CoreException;
public class PDOMASTAdapter {
@ -171,6 +173,16 @@ public class PDOMASTAdapter {
public IASTName getLastName() {
return this;
}
public IToken getLeadingSyntax() throws ExpansionOverlapsBoundaryException,
UnsupportedOperationException {
return fDelegate.getLeadingSyntax();
}
public IToken getTrailingSyntax() throws ExpansionOverlapsBoundaryException,
UnsupportedOperationException {
return fDelegate.getTrailingSyntax();
}
}
private static class AnonymousEnumeration implements IEnumeration {