mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 17:56:01 +02:00
fixing macros 72506.
Also make interface IMacro, change content assist to use it.
This commit is contained in:
parent
09dd8e4f22
commit
0558ecc1c9
9 changed files with 278 additions and 183 deletions
|
@ -80,7 +80,7 @@ public class IIncludeTests extends IntegratedCModelTest {
|
||||||
new String("resync_after_bad_parse_3"),
|
new String("resync_after_bad_parse_3"),
|
||||||
new String("invalid.h"), // C-spec does not allow this, but that's OK for our present purposes
|
new String("invalid.h"), // C-spec does not allow this, but that's OK for our present purposes
|
||||||
new String("myInclude1.h"),
|
new String("myInclude1.h"),
|
||||||
// new String("vers2.h")
|
new String("vers2.h")
|
||||||
};
|
};
|
||||||
assertEquals( getIncludeNameList.length, theIncludes.length );
|
assertEquals( getIncludeNameList.length, theIncludes.length );
|
||||||
for( int i=0; i<getIncludeNameList.length; i++ )
|
for( int i=0; i<getIncludeNameList.length; i++ )
|
||||||
|
|
|
@ -399,4 +399,30 @@ public class CompleteParsePluginTest extends TestCase {
|
||||||
assertEquals( i.next(), CallbackTracker.EXIT_COMPILATION_UNIT );
|
assertEquals( i.next(), CallbackTracker.EXIT_COMPILATION_UNIT );
|
||||||
assertFalse( i.hasNext() );
|
assertFalse( i.hasNext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBug72506() throws Exception{
|
||||||
|
String vers = "int i;\n"; //$NON-NLS-1$
|
||||||
|
String code = "#define INCFILE(x) vers ## x\n" + //$NON-NLS-1$
|
||||||
|
"#define xstr(x) str(x)\n" + //$NON-NLS-1$
|
||||||
|
"#define str(x) #x\n" + //$NON-NLS-1$
|
||||||
|
"#include xstr(INCFILE(2).h)\n"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
importFile( "vers2.h", vers ); //$NON-NLS-1$
|
||||||
|
IFile cpp = importFile( "code.cpp", code ); //$NON-NLS-1$
|
||||||
|
|
||||||
|
List calls = new ArrayList();
|
||||||
|
|
||||||
|
parse( cpp, calls );
|
||||||
|
|
||||||
|
Iterator i = calls.iterator();
|
||||||
|
assertEquals( i.next(), CallbackTracker.ENTER_COMPILATION_UNIT );
|
||||||
|
assertEquals( i.next(), CallbackTracker.ACCEPT_MACRO );
|
||||||
|
assertEquals( i.next(), CallbackTracker.ACCEPT_MACRO );
|
||||||
|
assertEquals( i.next(), CallbackTracker.ACCEPT_MACRO );
|
||||||
|
assertEquals( i.next(), CallbackTracker.ENTER_INCLUSION );
|
||||||
|
assertEquals( i.next(), CallbackTracker.ACCEPT_VARIABLE );
|
||||||
|
assertEquals( i.next(), CallbackTracker.EXIT_INCLUSION );
|
||||||
|
assertEquals( i.next(), CallbackTracker.EXIT_COMPILATION_UNIT );
|
||||||
|
assertFalse( i.hasNext() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1770,6 +1770,42 @@ public class Scanner2Test extends BaseScanner2Test
|
||||||
validateEOF();
|
validateEOF();
|
||||||
assertTrue( callback.problems.isEmpty() );
|
assertTrue( callback.problems.isEmpty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBug72506() throws Exception{
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
writer.write("#define INCFILE(x) ver ## x\n"); //$NON-NLS-1$
|
||||||
|
writer.write("#define xstr(x) str(x)\n"); //$NON-NLS-1$
|
||||||
|
writer.write("#define str(x) #x\n"); //$NON-NLS-1$
|
||||||
|
writer.write("xstr(INCFILE(2).h)\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
initializeScanner( writer.toString() );
|
||||||
|
validateString("ver2.h"); //$NON-NLS-1$
|
||||||
|
validateEOF();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBug72506_2() throws Exception{
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
writer.write("#define str(x) #x\n"); //$NON-NLS-1$
|
||||||
|
writer.write("#define A B\n"); //$NON-NLS-1$
|
||||||
|
writer.write("#define B A\n"); //$NON-NLS-1$
|
||||||
|
writer.write("str(B)\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
initializeScanner( writer.toString() );
|
||||||
|
validateString( "B" ); //$NON-NLS-1$
|
||||||
|
validateEOF();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMacroPastingError() throws Exception{
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
writer.write("#define m(expr) \\\r\n"); //$NON-NLS-1$
|
||||||
|
writer.write(" foo( #expr ) \r\n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
Callback callback = new Callback(ParserMode.COMPLETE_PARSE);
|
||||||
|
initializeScanner( writer.toString(), ParserMode.COMPLETE_PARSE, callback );
|
||||||
|
validateEOF();
|
||||||
|
assertTrue( callback.problems.isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2004 IBM Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Created on Sep 16, 2004
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.core.parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author aniefer
|
||||||
|
*/
|
||||||
|
public interface IMacro {
|
||||||
|
//For object-like macros these will be the same,
|
||||||
|
//for function-like macros, the signature includes the parameters
|
||||||
|
public char[] getSignature();
|
||||||
|
public char[] getName();
|
||||||
|
}
|
|
@ -10,11 +10,13 @@
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.parser.scanner2;
|
package org.eclipse.cdt.internal.core.parser.scanner2;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.parser.IMacro;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jcamelon
|
* @author jcamelon
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class DynamicStyleMacro {
|
public abstract class DynamicStyleMacro implements IMacro{
|
||||||
|
|
||||||
public abstract char [] execute();
|
public abstract char [] execute();
|
||||||
|
|
||||||
|
@ -24,4 +26,12 @@ public abstract class DynamicStyleMacro {
|
||||||
}
|
}
|
||||||
public final char [] name;
|
public final char [] name;
|
||||||
|
|
||||||
|
public char[] getSignature()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public char[] getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,35 @@ import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
|
||||||
public class FunctionStyleMacro extends ObjectStyleMacro {
|
public class FunctionStyleMacro extends ObjectStyleMacro {
|
||||||
|
|
||||||
public char[][] arglist;
|
public char[][] arglist;
|
||||||
|
private char[] sig = null;
|
||||||
public FunctionStyleMacro(char[] name, char[] expansion, char[][] arglist) {
|
public FunctionStyleMacro(char[] name, char[] expansion, char[][] arglist) {
|
||||||
super(name, expansion);
|
super(name, expansion);
|
||||||
this.arglist = arglist;
|
this.arglist = arglist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public char[] getSignature(){
|
||||||
|
if( sig != null )
|
||||||
|
return sig;
|
||||||
|
|
||||||
|
int len = name.length + 2 /*()*/;
|
||||||
|
for( int i = 0; i < arglist.length && arglist[i] != null; i++ ){
|
||||||
|
if( i + 1 < arglist.length && arglist[i+1] != null)
|
||||||
|
len += 1; /*,*/
|
||||||
|
len += arglist[i].length;
|
||||||
|
}
|
||||||
|
sig = new char[len];
|
||||||
|
System.arraycopy( name, 0, sig, 0, name.length );
|
||||||
|
sig[name.length] = '(';
|
||||||
|
int idx = name.length + 1;
|
||||||
|
for( int i = 0; i < arglist.length && arglist[i] != null; i++ ){
|
||||||
|
System.arraycopy( arglist[i], 0, sig, idx, arglist[i].length );
|
||||||
|
idx += arglist[i].length;
|
||||||
|
if( i + 1 < arglist.length && arglist[i+1] != null )
|
||||||
|
sig[idx++] = ',';
|
||||||
|
}
|
||||||
|
sig[idx] = ')';
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
public class Expansion {
|
public class Expansion {
|
||||||
|
|
||||||
public final CharArrayObjectMap definitions
|
public final CharArrayObjectMap definitions
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.parser.scanner2;
|
package org.eclipse.cdt.internal.core.parser.scanner2;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.parser.IMacro;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Doug Schaefer
|
* @author Doug Schaefer
|
||||||
*/
|
*/
|
||||||
public class ObjectStyleMacro {
|
public class ObjectStyleMacro implements IMacro{
|
||||||
|
|
||||||
public char[] name;
|
public char[] name;
|
||||||
public char[] expansion;
|
public char[] expansion;
|
||||||
|
@ -22,4 +24,12 @@ public class ObjectStyleMacro {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.expansion = expansion;
|
this.expansion = expansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public char[] getSignature() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getName(){
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.parser.CodeReader;
|
import org.eclipse.cdt.core.parser.CodeReader;
|
||||||
import org.eclipse.cdt.core.parser.EndOfFileException;
|
import org.eclipse.cdt.core.parser.EndOfFileException;
|
||||||
|
import org.eclipse.cdt.core.parser.IMacro;
|
||||||
import org.eclipse.cdt.core.parser.IParserLogService;
|
import org.eclipse.cdt.core.parser.IParserLogService;
|
||||||
import org.eclipse.cdt.core.parser.IProblem;
|
import org.eclipse.cdt.core.parser.IProblem;
|
||||||
import org.eclipse.cdt.core.parser.IScanner;
|
import org.eclipse.cdt.core.parser.IScanner;
|
||||||
|
@ -835,16 +836,13 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
|
|
||||||
private IToken newToken( int signal, char [] buffer )
|
private IToken newToken( int signal, char [] buffer )
|
||||||
{
|
{
|
||||||
if( bufferData[bufferStackPos] instanceof ObjectStyleMacro ||
|
if( bufferData[bufferStackPos] instanceof IMacro )
|
||||||
bufferData[bufferStackPos] instanceof FunctionStyleMacro )
|
|
||||||
{
|
{
|
||||||
int mostRelevant;
|
int mostRelevant;
|
||||||
for( mostRelevant = bufferStackPos; mostRelevant >= 0; --mostRelevant )
|
for( mostRelevant = bufferStackPos; mostRelevant >= 0; --mostRelevant )
|
||||||
if( bufferData[mostRelevant] instanceof InclusionData || bufferData[mostRelevant] instanceof CodeReader )
|
if( bufferData[mostRelevant] instanceof InclusionData || bufferData[mostRelevant] instanceof CodeReader )
|
||||||
break;
|
break;
|
||||||
if( bufferData[bufferStackPos] instanceof ObjectStyleMacro )
|
return new ImagedExpansionToken( signal, buffer, bufferPos[mostRelevant], ((IMacro)bufferData[bufferStackPos]).getName().length, getCurrentFilename(), getLineNumber( bufferPos[bufferStackPos] + 1));
|
||||||
return new ImagedExpansionToken( signal, buffer, bufferPos[mostRelevant], ((ObjectStyleMacro)bufferData[bufferStackPos]).name.length, getCurrentFilename(), getLineNumber( bufferPos[bufferStackPos] + 1) );
|
|
||||||
return new ImagedExpansionToken( signal, buffer, bufferPos[mostRelevant], ((FunctionStyleMacro)bufferData[bufferStackPos]).name.length, getCurrentFilename(), getLineNumber( bufferPos[bufferStackPos] + 1));
|
|
||||||
}
|
}
|
||||||
IToken i = new ImagedToken(signal, buffer, bufferPos[bufferStackPos] + 1 , getCurrentFilename(), getLineNumber( bufferPos[bufferStackPos] + 1));
|
IToken i = new ImagedToken(signal, buffer, bufferPos[bufferStackPos] + 1 , getCurrentFilename(), getLineNumber( bufferPos[bufferStackPos] + 1));
|
||||||
if( buffer != null && buffer.length == 0 )
|
if( buffer != null && buffer.length == 0 )
|
||||||
|
@ -896,19 +894,7 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
// Check for macro expansion
|
// Check for macro expansion
|
||||||
Object expObject = definitions.get(buffer, start, len);
|
Object expObject = definitions.get(buffer, start, len);
|
||||||
|
|
||||||
// but not if it has been expanded on the stack already
|
if (expObject != null && !isLimitReached() && shouldExpandMacro( (IMacro) expObject)) {
|
||||||
// i.e. recursion avoidance
|
|
||||||
if (expObject != null && !isLimitReached() )
|
|
||||||
for (int stackPos = bufferStackPos; stackPos >= 0; --stackPos)
|
|
||||||
if (bufferData[stackPos] != null
|
|
||||||
&& bufferData[stackPos] instanceof ObjectStyleMacro
|
|
||||||
&& CharArrayUtils.equals(buffer, start, len,
|
|
||||||
((ObjectStyleMacro)bufferData[stackPos]).name)) {
|
|
||||||
expObject = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expObject != null && !isLimitReached()) {
|
|
||||||
if (expObject instanceof FunctionStyleMacro) {
|
if (expObject instanceof FunctionStyleMacro) {
|
||||||
handleFunctionStyleMacro((FunctionStyleMacro)expObject, true);
|
handleFunctionStyleMacro((FunctionStyleMacro)expObject, true);
|
||||||
} else if (expObject instanceof ObjectStyleMacro) {
|
} else if (expObject instanceof ObjectStyleMacro) {
|
||||||
|
@ -948,6 +934,26 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param buffer
|
||||||
|
* @param start
|
||||||
|
* @param len
|
||||||
|
* @param expObject
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean shouldExpandMacro( IMacro macro ) {
|
||||||
|
// but not if it has been expanded on the stack already
|
||||||
|
// i.e. recursion avoidance
|
||||||
|
if( macro != null && !isLimitReached() )
|
||||||
|
for (int stackPos = bufferStackPos; stackPos >= 0; --stackPos)
|
||||||
|
if( bufferData[stackPos] != null && bufferData[stackPos] instanceof IMacro &&
|
||||||
|
CharArrayUtils.equals(macro.getName(), ((IMacro)bufferData[stackPos]).getName()) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private final boolean isLimitReached() {
|
private final boolean isLimitReached() {
|
||||||
|
@ -1521,6 +1527,7 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
}
|
}
|
||||||
if( t != null )
|
if( t != null )
|
||||||
{
|
{
|
||||||
|
t = replaceArgumentMacros( t );
|
||||||
if( (t[ t.length - 1 ] == t[0] ) && ( t[0] == '\"') )
|
if( (t[ t.length - 1 ] == t[0] ) && ( t[0] == '\"') )
|
||||||
{
|
{
|
||||||
local = true;
|
local = true;
|
||||||
|
@ -1702,14 +1709,19 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
boolean encounteredMultilineComment = false;
|
boolean encounteredMultilineComment = false;
|
||||||
while (bufferPos[bufferStackPos] + 1 < limit
|
while (bufferPos[bufferStackPos] + 1 < limit
|
||||||
&& buffer[bufferPos[bufferStackPos] + 1] != '\n') {
|
&& buffer[bufferPos[bufferStackPos] + 1] != '\n') {
|
||||||
|
//16.3.2-1 Each # preprocessing token in the replacement list for a function-like-macro shall
|
||||||
|
//be followed by a parameter as the next preprocessing token
|
||||||
if( arglist != null && !skipOverNonWhiteSpace( true ) ){
|
if( arglist != null && !skipOverNonWhiteSpace( true ) ){
|
||||||
++bufferPos[bufferStackPos];
|
++bufferPos[bufferStackPos]; //advances us to the #
|
||||||
if( skipOverWhiteSpace() )
|
if( skipOverWhiteSpace() )
|
||||||
encounteredMultilineComment = true;
|
encounteredMultilineComment = true;
|
||||||
|
++bufferPos[bufferStackPos]; //advances us past the # (or last whitespace)
|
||||||
boolean isArg = false;
|
boolean isArg = false;
|
||||||
for( int i = 0; i < arglist.length && arglist[i] != null; i++ ){
|
for( int i = 0; i < arglist.length && arglist[i] != null; i++ ){
|
||||||
if( CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], arglist[i].length, arglist[i] ) ){
|
if( CharArrayUtils.equals( buffer, bufferPos[bufferStackPos], arglist[i].length, arglist[i] ) ){
|
||||||
isArg = true;
|
isArg = true;
|
||||||
|
//advance us to the end of the arg
|
||||||
|
bufferPos[bufferStackPos] += arglist[i].length - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2145,31 +2157,29 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skipOverMacroArg() {
|
private int skipOverMacroArg(){
|
||||||
char[] buffer = bufferStack[bufferStackPos];
|
char [] buffer = bufferStack[bufferStackPos];
|
||||||
int limit = bufferLimit[bufferStackPos];
|
int limit = bufferLimit[bufferStackPos];
|
||||||
|
int argEnd = bufferPos[bufferStackPos]--;
|
||||||
while (++bufferPos[bufferStackPos] < limit) {
|
int nesting = 0;
|
||||||
|
while (++bufferPos[bufferStackPos] < limit) {
|
||||||
switch (buffer[bufferPos[bufferStackPos]]) {
|
switch (buffer[bufferPos[bufferStackPos]]) {
|
||||||
case ' ':
|
case '(':
|
||||||
case '\t':
|
++nesting;
|
||||||
case '\r':
|
break;
|
||||||
case '\n':
|
case ')':
|
||||||
|
if( nesting == 0 ){
|
||||||
|
--bufferPos[bufferStackPos];
|
||||||
|
return argEnd;
|
||||||
|
}
|
||||||
|
--nesting;
|
||||||
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
case ')':
|
if( nesting == 0 ){
|
||||||
case '(':
|
--bufferPos[bufferStackPos];
|
||||||
case '<':
|
return argEnd;
|
||||||
case '>':
|
}
|
||||||
--bufferPos[bufferStackPos];
|
break;
|
||||||
return;
|
|
||||||
case '\\':
|
|
||||||
int pos = bufferPos[bufferStackPos];
|
|
||||||
if (pos + 1 < limit && buffer[pos + 1] == '\n') {
|
|
||||||
// \n is whitespace
|
|
||||||
--bufferPos[bufferStackPos];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '"':
|
case '"':
|
||||||
boolean escaped = false;
|
boolean escaped = false;
|
||||||
loop:
|
loop:
|
||||||
|
@ -2190,8 +2200,11 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
argEnd = bufferPos[bufferStackPos];
|
||||||
|
skipOverWhiteSpace();
|
||||||
}
|
}
|
||||||
--bufferPos[bufferStackPos];
|
--bufferPos[bufferStackPos];
|
||||||
|
return argEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skipOverIdentifier() {
|
private void skipOverIdentifier() {
|
||||||
|
@ -2274,73 +2287,23 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
CharArrayObjectMap argmap = new CharArrayObjectMap(arglist.length);
|
CharArrayObjectMap argmap = new CharArrayObjectMap(arglist.length);
|
||||||
|
|
||||||
while (bufferPos[bufferStackPos] < limit) {
|
while (bufferPos[bufferStackPos] < limit) {
|
||||||
|
skipOverWhiteSpace();
|
||||||
|
|
||||||
|
if (buffer[++bufferPos[bufferStackPos]] == ')') {
|
||||||
|
// end of macro
|
||||||
|
break;
|
||||||
|
} else if( buffer[bufferPos[bufferStackPos]] == ',' ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (++currarg >= arglist.length || arglist[currarg] == null){
|
if (++currarg >= arglist.length || arglist[currarg] == null){
|
||||||
// too many args
|
// too many args
|
||||||
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, bufferPos[bufferStackPos], macro.name );
|
handleProblem( IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, bufferPos[bufferStackPos], macro.name );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
skipOverWhiteSpace();
|
|
||||||
|
|
||||||
int pos = ++bufferPos[bufferStackPos];
|
int argstart = bufferPos[bufferStackPos];
|
||||||
char c = buffer[pos];
|
int argend = skipOverMacroArg();
|
||||||
if (c == ')') {
|
|
||||||
// end of macro
|
|
||||||
break;
|
|
||||||
} else if (c == ',') {
|
|
||||||
// empty arg
|
|
||||||
argmap.put(arglist[currarg], emptyCharArray);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// peel off the arg
|
|
||||||
--bufferPos[bufferStackPos];
|
|
||||||
int argend = bufferPos[bufferStackPos];
|
|
||||||
int argstart = argend + 1;
|
|
||||||
|
|
||||||
// Loop looking for end of argument
|
|
||||||
int argparens = 0;
|
|
||||||
// int startOffset = -1;
|
|
||||||
while (bufferPos[bufferStackPos] < limit) {
|
|
||||||
// if( bufferPos[bufferStackPos] == startOffset )
|
|
||||||
// ++bufferPos[bufferStackPos];
|
|
||||||
// startOffset = bufferPos[bufferStackPos];
|
|
||||||
skipOverMacroArg();
|
|
||||||
argend = bufferPos[bufferStackPos];
|
|
||||||
skipOverWhiteSpace();
|
|
||||||
|
|
||||||
if (++bufferPos[bufferStackPos] >= limit)
|
|
||||||
break;
|
|
||||||
c = buffer[bufferPos[bufferStackPos]];
|
|
||||||
if (c == '(' || c == '<')
|
|
||||||
++argparens;
|
|
||||||
else if (c == '>')
|
|
||||||
--argparens;
|
|
||||||
else if (c == ')') {
|
|
||||||
if (argparens == 0)
|
|
||||||
break;
|
|
||||||
--argparens;
|
|
||||||
} else if (c == ',') {
|
|
||||||
if (argparens == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (c == '\n') {
|
|
||||||
// eat it and continue
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// start of next macro arg
|
|
||||||
--bufferPos[bufferStackPos];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
skipOverWhiteSpace();
|
|
||||||
while (++bufferPos[bufferStackPos] < limit) {
|
|
||||||
if (buffer[bufferPos[bufferStackPos]] != '\n')
|
|
||||||
break;
|
|
||||||
skipOverWhiteSpace();
|
|
||||||
}
|
|
||||||
--bufferPos[bufferStackPos];
|
|
||||||
}
|
|
||||||
|
|
||||||
char[] arg = emptyCharArray;
|
char[] arg = emptyCharArray;
|
||||||
int arglen = argend - argstart + 1;
|
int arglen = argend - argstart + 1;
|
||||||
|
@ -2349,15 +2312,11 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
System.arraycopy(buffer, argstart, arg, 0, arglen);
|
System.arraycopy(buffer, argstart, arg, 0, arglen);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO 16.3.1 We are supposed to completely macro replace the arguments before
|
//16.3.1 completely macro replace the arguments before substituting them in
|
||||||
//substituting them in, this is only a partial replacement of object macros,
|
|
||||||
//we may need a full solution later.
|
|
||||||
arg = replaceArgumentMacros( arg );
|
arg = replaceArgumentMacros( arg );
|
||||||
argmap.put(arglist[currarg], arg);
|
argmap.put(arglist[currarg], arg);
|
||||||
|
|
||||||
if (c == ')')
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int numArgs = arglist.length;
|
int numArgs = arglist.length;
|
||||||
for( int i = 0; i < arglist.length; i++ ){
|
for( int i = 0; i < arglist.length; i++ ){
|
||||||
if( arglist[i] == null ){
|
if( arglist[i] == null ){
|
||||||
|
@ -2378,33 +2337,74 @@ public class Scanner2 implements IScanner, IScannerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
private char[] replaceArgumentMacros( char [] arg ){
|
private char[] replaceArgumentMacros( char [] arg ){
|
||||||
// Check for macro expansion
|
int limit = arg.length;
|
||||||
Object expObject = definitions.get(arg, 0, arg.length);
|
int start = -1, end = -1;
|
||||||
|
Object expObject = null;
|
||||||
// but not if it has been expanded on the stack already
|
for( int pos = 0; pos < limit; pos++ ){
|
||||||
// i.e. recursion avoidance
|
char c = arg[pos];
|
||||||
if (expObject != null){
|
if( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ||
|
||||||
for (int stackPos = bufferStackPos; stackPos >= 0; --stackPos){
|
Character.isLetter( c ) || scannerExtension.isValidIdentifierStartCharacter( c ) )
|
||||||
if (bufferData[stackPos] != null
|
{
|
||||||
&& bufferData[stackPos] instanceof ObjectStyleMacro
|
start = pos;
|
||||||
&& CharArrayUtils.equals(arg, ((ObjectStyleMacro)bufferData[stackPos]).name))
|
while (++pos < limit) {
|
||||||
{
|
c = arg[pos];
|
||||||
expObject = null;
|
if( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') ||
|
||||||
|
scannerExtension.isValidIdentifierCharacter(c) || Character.isUnicodeIdentifierPart(c) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
end = pos - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( start != -1 && end >= start ){
|
||||||
|
//Check for macro expansion
|
||||||
|
expObject = definitions.get(arg, start, ( end - start + 1 ) );
|
||||||
|
if( expObject == null || !shouldExpandMacro( (IMacro) expObject) ){
|
||||||
|
expObject = null;
|
||||||
|
start = -1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
//else, break and expand macro
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( expObject == null )
|
if( expObject == null )
|
||||||
return arg;
|
return arg;
|
||||||
|
|
||||||
if (expObject instanceof ObjectStyleMacro) {
|
char [] expansion = null;
|
||||||
|
if( expObject instanceof FunctionStyleMacro ){
|
||||||
|
FunctionStyleMacro expMacro = (FunctionStyleMacro) expObject;
|
||||||
|
pushContext( ( start == 0 ) ? arg : CharArrayUtils.extract( arg, start, arg.length - start + 1 ) );
|
||||||
|
bufferPos[bufferStackPos] += end - start + 1;
|
||||||
|
expansion = handleFunctionStyleMacro( expMacro, false );
|
||||||
|
end = bufferPos[bufferStackPos];
|
||||||
|
popContext();
|
||||||
|
} else if (expObject instanceof ObjectStyleMacro) {
|
||||||
ObjectStyleMacro expMacro = (ObjectStyleMacro)expObject;
|
ObjectStyleMacro expMacro = (ObjectStyleMacro)expObject;
|
||||||
return expMacro.expansion;
|
expansion = expMacro.expansion;
|
||||||
} else if (expObject instanceof char[]) {
|
} else if (expObject instanceof char[]) {
|
||||||
return (char[])expObject;
|
expansion = (char[])expObject;
|
||||||
|
} else if( expObject instanceof DynamicStyleMacro ){
|
||||||
|
DynamicStyleMacro expMacro = (DynamicStyleMacro) expObject;
|
||||||
|
expansion = expMacro.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( expansion != null ){
|
||||||
|
int newlength = start + expansion.length + ( limit - end - 1 );
|
||||||
|
char [] result = new char [ newlength ];
|
||||||
|
System.arraycopy( arg, 0, result, 0, start);
|
||||||
|
System.arraycopy( expansion, 0, result, start, expansion.length );
|
||||||
|
if( arg.length > end + 1 )
|
||||||
|
System.arraycopy( arg, end + 1, result, start + expansion.length, limit - end - 1 );
|
||||||
|
|
||||||
|
//we need to put the macro on the context stack in order to detect recursive macros
|
||||||
|
pushContext( emptyCharArray, expObject );
|
||||||
|
arg = replaceArgumentMacros( result ); //rescan for more macros
|
||||||
|
popContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,13 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.model.CoreModel;
|
import org.eclipse.cdt.core.model.CoreModel;
|
||||||
import org.eclipse.cdt.core.model.ICElement;
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||||
import org.eclipse.cdt.core.parser.CodeReader;
|
import org.eclipse.cdt.core.parser.CodeReader;
|
||||||
|
import org.eclipse.cdt.core.parser.IMacro;
|
||||||
import org.eclipse.cdt.core.parser.IParser;
|
import org.eclipse.cdt.core.parser.IParser;
|
||||||
import org.eclipse.cdt.core.parser.IScanner;
|
import org.eclipse.cdt.core.parser.IScanner;
|
||||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||||
|
@ -57,9 +55,9 @@ import org.eclipse.cdt.core.parser.ast.IASTVariable;
|
||||||
import org.eclipse.cdt.core.parser.ast.IASTCompletionNode.CompletionKind;
|
import org.eclipse.cdt.core.parser.ast.IASTCompletionNode.CompletionKind;
|
||||||
import org.eclipse.cdt.core.parser.ast.IASTNode.ILookupResult;
|
import org.eclipse.cdt.core.parser.ast.IASTNode.ILookupResult;
|
||||||
import org.eclipse.cdt.core.parser.ast.IASTNode.LookupKind;
|
import org.eclipse.cdt.core.parser.ast.IASTNode.LookupKind;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.internal.core.CharOperation;
|
import org.eclipse.cdt.internal.core.CharOperation;
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner2.FunctionStyleMacro;
|
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner2.ObjectStyleMacro;
|
|
||||||
import org.eclipse.cdt.internal.ui.CUIMessages;
|
import org.eclipse.cdt.internal.ui.CUIMessages;
|
||||||
import org.eclipse.cdt.internal.ui.util.IDebugLogConstants;
|
import org.eclipse.cdt.internal.ui.util.IDebugLogConstants;
|
||||||
import org.eclipse.cdt.internal.ui.util.Util;
|
import org.eclipse.cdt.internal.ui.util.Util;
|
||||||
|
@ -82,7 +80,7 @@ public class CompletionEngine implements RelevanceConstants {
|
||||||
int completionLength = 0;
|
int completionLength = 0;
|
||||||
int completionOrigin = 0;
|
int completionOrigin = 0;
|
||||||
IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore();
|
IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore();
|
||||||
private Map macroMap = null;
|
private CharArrayObjectMap macroMap = null;
|
||||||
private ContentAssistElementRequestor elementRequestor = null;
|
private ContentAssistElementRequestor elementRequestor = null;
|
||||||
|
|
||||||
private static final String exceptionKeyword = "..."; //$NON-NLS-1$
|
private static final String exceptionKeyword = "..."; //$NON-NLS-1$
|
||||||
|
@ -190,7 +188,7 @@ public class CompletionEngine implements RelevanceConstants {
|
||||||
result = parser.parse(completionOffset);
|
result = parser.parse(completionOffset);
|
||||||
log("Time spent in Parser = "+ ( System.currentTimeMillis() - parserTime ) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
|
log("Time spent in Parser = "+ ( System.currentTimeMillis() - parserTime ) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
macroMap = scanner.getDefinitions();
|
macroMap = scanner.getRealDefinitions();
|
||||||
} catch (ParseError e ) {
|
} catch (ParseError e ) {
|
||||||
if(e.getErrorKind() == ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED){
|
if(e.getErrorKind() == ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED){
|
||||||
log("Timeout received !!!!!! "); //$NON-NLS-1$;
|
log("Timeout received !!!!!! "); //$NON-NLS-1$;
|
||||||
|
@ -443,54 +441,21 @@ public class CompletionEngine implements RelevanceConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List lookupMacros(String prefix){
|
private List lookupMacros(String prefix){
|
||||||
Set keySet = new TreeSet(macroMap.keySet());
|
//simply doing a linear search on the keys will be faster than sorting them
|
||||||
Iterator i = keySet.iterator();
|
//and then searching the sorted list.
|
||||||
|
char [] prefixArray = prefix.toCharArray();
|
||||||
|
char [] key;
|
||||||
|
|
||||||
final int length = prefix.length();
|
final int length = prefix.length();
|
||||||
String newPrefix = prefix.toUpperCase();
|
|
||||||
List resultSet = new ArrayList();
|
List resultSet = new ArrayList();
|
||||||
String key = null;
|
for( int i = 0; i < macroMap.size(); i++ ){
|
||||||
String value = null; //$NON-NLS-1$
|
key = macroMap.keyAt( i );
|
||||||
while( i.hasNext() )
|
if( key.length < length )
|
||||||
{
|
|
||||||
key = (String) i.next();
|
|
||||||
if( key.length() < length )
|
|
||||||
continue;
|
continue;
|
||||||
|
if( CharArrayUtils.equals( key, 0, length, prefixArray, true ) ){
|
||||||
if(key.length() > length) {
|
IMacro macro = (IMacro) macroMap.getAt( i );
|
||||||
value = key.substring(0, length).toUpperCase();
|
resultSet.add( String.valueOf( macro.getSignature() ) );
|
||||||
}else {
|
}
|
||||||
value = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( value.equals( newPrefix ) ) {
|
|
||||||
Object macroD = macroMap.get(key);
|
|
||||||
if( macroD instanceof FunctionStyleMacro )
|
|
||||||
{
|
|
||||||
FunctionStyleMacro f = ((FunctionStyleMacro)macroD);
|
|
||||||
StringBuffer buffer = new StringBuffer( String.valueOf( f.name ));
|
|
||||||
buffer.append( "("); //$NON-NLS-1$
|
|
||||||
if( f.arglist != null )
|
|
||||||
{
|
|
||||||
for( int j = 0; j < f.arglist.length; ++j )
|
|
||||||
{
|
|
||||||
if( f.arglist[j] != null )
|
|
||||||
buffer.append( f.arglist[j]);
|
|
||||||
if( j != f.arglist.length -1 && f.arglist[j+1] != null )
|
|
||||||
buffer.append( ","); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.append( ")"); //$NON-NLS-1$
|
|
||||||
String result = buffer.toString();
|
|
||||||
resultSet.add( result );
|
|
||||||
}
|
|
||||||
else if (macroD instanceof ObjectStyleMacro )
|
|
||||||
{
|
|
||||||
String v = String.valueOf( ((ObjectStyleMacro)macroD).name);
|
|
||||||
resultSet.add( v );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( key.compareTo( prefix ) > 0 )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return resultSet;
|
return resultSet;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue