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:
parent
10b2bb8da5
commit
dd5413a3a2
18 changed files with 632 additions and 19 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -59,7 +61,15 @@ public class LocationMap implements ILocationResolver {
|
|||
// stuff computed on demand
|
||||
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,7 +402,11 @@ public class LocationMap implements ILocationResolver {
|
|||
return fRootContext.findMappedFileLocation(sequenceNumber, length);
|
||||
}
|
||||
|
||||
public char[] getUnpreprocessedSignature(IASTFileLocation loc) {
|
||||
public int convertToSequenceEndNumber(int sequenceNumber) {
|
||||
return fRootContext.convertToSequenceEndNumber(sequenceNumber);
|
||||
}
|
||||
|
||||
public char[] getUnpreprocessedSignature(IASTFileLocation loc) {
|
||||
ASTFileLocation floc= convertFileLocation(loc);
|
||||
if (floc == null) {
|
||||
return CharArrayUtils.EMPTY;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue