1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 10:46:02 +02:00
John Camelon 2004-05-11 02:47:15 +00:00
parent 5bbba8f2a5
commit 1ff19a66bd
14 changed files with 225 additions and 14 deletions

View file

@ -46,7 +46,6 @@ import org.eclipse.cdt.core.parser.ast.IASTVariableReference;
import org.eclipse.cdt.core.parser.ast.gcc.IASTGCCExpression; import org.eclipse.cdt.core.parser.ast.gcc.IASTGCCExpression;
import org.eclipse.cdt.core.parser.ast.gcc.IASTGCCSimpleTypeSpecifier; import org.eclipse.cdt.core.parser.ast.gcc.IASTGCCSimpleTypeSpecifier;
import org.eclipse.cdt.internal.core.parser.ParserException; import org.eclipse.cdt.internal.core.parser.ParserException;
import org.eclipse.ui.views.tasklist.TaskList;
/** /**
@ -1809,4 +1808,28 @@ public class CompleteParseASTTest extends CompleteParseBaseTest
assertFalse( i.hasNext() ); assertFalse( i.hasNext() );
} }
public void testDestructorReference() throws Exception
{
Writer writer = new StringWriter();
writer.write( "class ABC {\n"); //$NON-NLS-1$
writer.write( " public:\n"); //$NON-NLS-1$
writer.write( " ~ABC(){ }\n"); //$NON-NLS-1$
writer.write( "};\n"); //$NON-NLS-1$
writer.write( "int main() { ABC * abc = new ABC();\n"); //$NON-NLS-1$
writer.write( "abc->~ABC();\n"); //$NON-NLS-1$
writer.write( "}\n"); //$NON-NLS-1$
Iterator declarations = parse( writer.toString() ).getDeclarations();
IASTClassSpecifier ABC = (IASTClassSpecifier) ((IASTAbstractTypeSpecifierDeclaration)declarations.next()).getTypeSpecifier();
IASTFunction main = (IASTFunction) declarations.next();
assertFalse( declarations.hasNext() );
Iterator members = getDeclarations(ABC);
IASTFunction destructor = (IASTFunction) members.next();
assertFalse( members.hasNext() );
Iterator localVariables = getDeclarations( main );
IASTVariable variable = (IASTVariable) localVariables.next();
assertFalse( localVariables.hasNext() );
assertAllReferences( 4, createTaskList( new Task( ABC, 2 ), new Task( variable ), new Task( destructor )));
}
} }

View file

@ -215,7 +215,6 @@ public class SelectionParseTest extends CompleteParseBaseTest {
IASTNamespaceDefinition namespace = (IASTNamespaceDefinition) node; IASTNamespaceDefinition namespace = (IASTNamespaceDefinition) node;
assertEquals( namespace.getName(), "Muppets"); //$NON-NLS-1$ assertEquals( namespace.getName(), "Muppets"); //$NON-NLS-1$
assertEquals( namespace.getStartingLine(), 1 ); assertEquals( namespace.getStartingLine(), 1 );
} }
public void testBug61613() throws Exception public void testBug61613() throws Exception
@ -235,7 +234,58 @@ public class SelectionParseTest extends CompleteParseBaseTest {
assertTrue( node instanceof IASTClassSpecifier ); assertTrue( node instanceof IASTClassSpecifier );
IASTClassSpecifier foo = (IASTClassSpecifier) node; IASTClassSpecifier foo = (IASTClassSpecifier) node;
assertEquals( foo.getName(), "Foo"); //$NON-NLS-1$ assertEquals( foo.getName(), "Foo"); //$NON-NLS-1$
}
public void testBug60038() throws Exception
{
Writer writer = new StringWriter();
writer.write( "class Gonzo {\n"); //$NON-NLS-1$
writer.write( "public:\n"); //$NON-NLS-1$
writer.write( "Gonzo( const Gonzo & other ){}\n"); //$NON-NLS-1$
writer.write( "Gonzo() {}\n"); //$NON-NLS-1$
writer.write( "~Gonzo(){}\n"); //$NON-NLS-1$
writer.write( "};\n"); //$NON-NLS-1$
writer.write( "int main(int argc, char **argv) {\n"); //$NON-NLS-1$
writer.write( " Gonzo * g = new Gonzo();\n"); //$NON-NLS-1$
writer.write( " Gonzo * g2 = new Gonzo( *g );\n"); //$NON-NLS-1$
writer.write( " g->~Gonzo();\n"); //$NON-NLS-1$
writer.write( " return (int) g2;\n"); //$NON-NLS-1$
writer.write( "}\n"); //$NON-NLS-1$
String code = writer.toString();
for( int i = 0; i < 3; ++i )
{
int startOffset = 0, endOffset = 0;
switch( i )
{
case 0:
startOffset = code.indexOf( "new Gonzo()") + 4; //$NON-NLS-1$
endOffset = startOffset + 5;
break;
case 1:
startOffset = code.indexOf( "new Gonzo( ") + 4; //$NON-NLS-1$
endOffset = startOffset + 5;
break;
default:
startOffset = code.indexOf( "->~") + 2; //$NON-NLS-1$
endOffset = startOffset + 6;
}
IASTNode node = parse( code, startOffset, endOffset );
assertTrue( node instanceof IASTMethod );
IASTMethod method = (IASTMethod) node;
switch( i )
{
case 0:
case 1:
assertTrue( method.isConstructor() );
assertFalse( method.isDestructor() );
break;
default:
assertFalse( method.isConstructor() );
assertTrue( method.isDestructor() );
break;
}
}
} }
} }

View file

@ -231,6 +231,8 @@ public interface IASTExpression extends ISourceElementCallbackDelegate, IASTNode
this == IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION || this == IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION ||
this == IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS || this == IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS ||
this == IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP || this == IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP ||
this == IASTExpression.Kind.POSTFIX_ARROW_DESTRUCTOR ||
this == IASTExpression.Kind.POSTFIX_DOT_DESTRUCTOR ||
this == IASTExpression.Kind.PM_DOTSTAR || this == IASTExpression.Kind.PM_DOTSTAR ||
this == IASTExpression.Kind.PM_ARROWSTAR ) this == IASTExpression.Kind.PM_ARROWSTAR )
return true; return true;

View file

@ -277,4 +277,11 @@ public interface IASTFactory
*/ */
public boolean validateDirectMemberOperation(IASTNode node); public boolean validateDirectMemberOperation(IASTNode node);
/**
* @param ourScope
* @param newDescriptor TODO
* @return
*/
public IASTNode lookupConstructor(IASTScope ourScope, IASTNewExpressionDescriptor newDescriptor);
} }

View file

@ -14,6 +14,7 @@ import java.util.Iterator;
import org.eclipse.cdt.core.parser.Enum; import org.eclipse.cdt.core.parser.Enum;
import org.eclipse.cdt.core.parser.ISourceElementCallbackDelegate; import org.eclipse.cdt.core.parser.ISourceElementCallbackDelegate;
import org.eclipse.cdt.core.parser.ITokenDuple;
/** /**
* @author jcamelon * @author jcamelon
@ -43,5 +44,10 @@ public interface IASTInitializerClause extends ISourceElementCallbackDelegate{
public void setOwnerVariableDeclaration( IASTVariable declaration ); public void setOwnerVariableDeclaration( IASTVariable declaration );
public IASTVariable getOwnerVariableDeclaration(); public IASTVariable getOwnerVariableDeclaration();
/**
* @param finalDuple
* @return
*/
public IASTExpression findExpressionForDuple(ITokenDuple finalDuple) throws ASTNotImplementedException;
} }

View file

@ -2389,6 +2389,8 @@ public class ExpressionParser implements IExpressionParser, IParserData {
setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, KeywordSets.Key.EMPTY, firstExpression, memberCompletionKind ); setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, KeywordSets.Key.EMPTY, firstExpression, memberCompletionKind );
secondExpression = primaryExpression(scope, CompletionKind.MEMBER_REFERENCE, key); secondExpression = primaryExpression(scope, CompletionKind.MEMBER_REFERENCE, key);
if( secondExpression != null && secondExpression.getExpressionKind() == Kind.ID_EXPRESSION && secondExpression.getIdExpression().indexOf( '~') != -1 )
memberCompletionKind = Kind.POSTFIX_DOT_DESTRUCTOR;
try try
{ {
@ -2430,6 +2432,8 @@ public class ExpressionParser implements IExpressionParser, IParserData {
setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, KeywordSets.Key.EMPTY, firstExpression, arrowCompletionKind ); setCompletionValues(scope, CompletionKind.MEMBER_REFERENCE, KeywordSets.Key.EMPTY, firstExpression, arrowCompletionKind );
secondExpression = primaryExpression(scope, CompletionKind.MEMBER_REFERENCE, key); secondExpression = primaryExpression(scope, CompletionKind.MEMBER_REFERENCE, key);
if( secondExpression != null && secondExpression.getExpressionKind() == Kind.ID_EXPRESSION && secondExpression.getIdExpression().indexOf( '~') != -1 )
arrowCompletionKind = Kind.POSTFIX_ARROW_DESTRUCTOR;
try try
{ {
firstExpression = firstExpression =
@ -2680,6 +2684,7 @@ public class ExpressionParser implements IExpressionParser, IParserData {
case IToken.tIDENTIFIER : case IToken.tIDENTIFIER :
case IToken.tCOLONCOLON : case IToken.tCOLONCOLON :
case IToken.t_operator : case IToken.t_operator :
case IToken.tCOMPL:
ITokenDuple duple = null; ITokenDuple duple = null;
IToken mark = mark(); IToken mark = mark();

View file

@ -29,10 +29,12 @@ import org.eclipse.cdt.core.parser.ast.IASTDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTEnumerator; import org.eclipse.cdt.core.parser.ast.IASTEnumerator;
import org.eclipse.cdt.core.parser.ast.IASTExpression; import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTFunction; import org.eclipse.cdt.core.parser.ast.IASTFunction;
import org.eclipse.cdt.core.parser.ast.IASTInitializerClause;
import org.eclipse.cdt.core.parser.ast.IASTNode; import org.eclipse.cdt.core.parser.ast.IASTNode;
import org.eclipse.cdt.core.parser.ast.IASTOffsetableNamedElement; import org.eclipse.cdt.core.parser.ast.IASTOffsetableNamedElement;
import org.eclipse.cdt.core.parser.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.parser.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTScope; import org.eclipse.cdt.core.parser.ast.IASTScope;
import org.eclipse.cdt.core.parser.ast.IASTVariable;
import org.eclipse.cdt.core.parser.extension.IParserExtension; import org.eclipse.cdt.core.parser.extension.IParserExtension;
import org.eclipse.cdt.internal.core.parser.token.OffsetDuple; import org.eclipse.cdt.internal.core.parser.token.OffsetDuple;
import org.eclipse.cdt.internal.core.parser.token.TokenDuple; import org.eclipse.cdt.internal.core.parser.token.TokenDuple;
@ -61,17 +63,20 @@ public class SelectionParser extends ContextualParser {
if( value != null && scanner.isOnTopContext() ) if( value != null && scanner.isOnTopContext() )
{ {
TraceUtil.outputTrace(log, "IToken provided w/offsets ", null, value.getOffset(), " & ", value.getEndOffset() ); //$NON-NLS-1$ //$NON-NLS-2$ TraceUtil.outputTrace(log, "IToken provided w/offsets ", null, value.getOffset(), " & ", value.getEndOffset() ); //$NON-NLS-1$ //$NON-NLS-2$
boolean change = false;
if( value.getOffset() == offsetRange.getFloorOffset() ) if( value.getOffset() == offsetRange.getFloorOffset() )
{ {
TraceUtil.outputTrace(log, "Offset Floor Hit w/token \"", null, value.getImage(), "\"", null ); //$NON-NLS-1$ //$NON-NLS-2$ TraceUtil.outputTrace(log, "Offset Floor Hit w/token \"", null, value.getImage(), "\"", null ); //$NON-NLS-1$ //$NON-NLS-2$
firstTokenOfDuple = value; firstTokenOfDuple = value;
change = true;
} }
if( value.getEndOffset() == offsetRange.getCeilingOffset() ) if( value.getEndOffset() == offsetRange.getCeilingOffset() )
{ {
TraceUtil.outputTrace(log, "Offset Ceiling Hit w/token \"", null, value.getImage(), "\"", null ); //$NON-NLS-1$ //$NON-NLS-2$ TraceUtil.outputTrace(log, "Offset Ceiling Hit w/token \"", null, value.getImage(), "\"", null ); //$NON-NLS-1$ //$NON-NLS-2$
change = true;
lastTokenOfDuple = value; lastTokenOfDuple = value;
} }
if( tokenDupleCompleted() ) if( change && tokenDupleCompleted() )
{ {
if ( ourScope == null ) if ( ourScope == null )
ourScope = getCompletionScope(); ourScope = getCompletionScope();
@ -194,6 +199,19 @@ public class SelectionParser extends ContextualParser {
return contextNode; return contextNode;
} }
try { try {
if( ourKind == IASTCompletionNode.CompletionKind.NEW_TYPE_REFERENCE )
{
if( contextNode instanceof IASTVariable )
{
IASTInitializerClause initializer = ((IASTVariable)contextNode).getInitializerClause();
if( initializer != null )
{
IASTExpression ownerExpression = initializer.findExpressionForDuple( finalDuple );
return astFactory.lookupSymbolInContext( ourScope, finalDuple, ownerExpression );
}
}
}
return astFactory.lookupSymbolInContext( ourScope, finalDuple, null ); return astFactory.lookupSymbolInContext( ourScope, finalDuple, null );
} catch (ASTNotImplementedException e) { } catch (ASTNotImplementedException e) {
return null; return null;

View file

@ -267,4 +267,12 @@ public abstract class ASTExpression extends ASTNode implements IASTExpression
public IASTNewExpressionDescriptor getNewExpressionDescriptor() { public IASTNewExpressionDescriptor getNewExpressionDescriptor() {
return null; return null;
} }
/**
* @param finalDuple
* @return
*/
public IASTExpression findNewDescriptor(ITokenDuple finalDuple) {
return null;
}
} }

View file

@ -15,6 +15,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import org.eclipse.cdt.core.parser.ISourceElementRequestor; import org.eclipse.cdt.core.parser.ISourceElementRequestor;
import org.eclipse.cdt.core.parser.ITokenDuple;
import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
import org.eclipse.cdt.core.parser.ast.IASTExpression; import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTInitializerClause; import org.eclipse.cdt.core.parser.ast.IASTInitializerClause;
import org.eclipse.cdt.core.parser.ast.IASTVariable; import org.eclipse.cdt.core.parser.ast.IASTVariable;
@ -127,4 +129,21 @@ public class ASTInitializerClause implements IASTInitializerClause
{ {
return references; return references;
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.ast.IASTInitializerClause#findExpressionForDuple(org.eclipse.cdt.core.parser.ITokenDuple)
*/
public IASTExpression findExpressionForDuple(ITokenDuple finalDuple) throws ASTNotImplementedException {
if( kind == IASTInitializerClause.Kind.EMPTY ) return null;
if( kind == IASTInitializerClause.Kind.ASSIGNMENT_EXPRESSION ||
kind == Kind.DESIGNATED_ASSIGNMENT_EXPRESSION )
return ((ASTExpression)assignmentExpression).findNewDescriptor( finalDuple );
Iterator i = getInitializers();
while( i.hasNext() )
{
IASTInitializerClause clause = (IASTInitializerClause) i.next();
IASTExpression e = clause.findExpressionForDuple(finalDuple);
if( e != null ) return e;
}
return null;
}
} }

View file

@ -13,6 +13,8 @@ package org.eclipse.cdt.internal.core.parser.ast.complete;
import java.util.List; import java.util.List;
import org.eclipse.cdt.core.parser.ISourceElementRequestor; import org.eclipse.cdt.core.parser.ISourceElementRequestor;
import org.eclipse.cdt.core.parser.ITokenDuple;
import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTTypeId; import org.eclipse.cdt.core.parser.ast.IASTTypeId;
/** /**
@ -58,4 +60,14 @@ public class ASTNewExpression extends ASTExpression {
typeId.acceptElement(requestor); typeId.acceptElement(requestor);
newDescriptor.acceptElement(requestor); newDescriptor.acceptElement(requestor);
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.ast.complete.ASTExpression#findNewDescriptor(org.eclipse.cdt.core.parser.ITokenDuple)
*/
public IASTExpression findNewDescriptor(ITokenDuple finalDuple) {
if( ((ASTTypeId)typeId).getTokenDuple().contains( finalDuple ))
return this;
return null;
}
} }

View file

@ -1256,13 +1256,8 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
} }
private IContainerSymbol getSearchScope (Kind kind, IASTExpression lhs, IContainerSymbol startingScope) throws ASTSemanticException{ private IContainerSymbol getSearchScope (Kind kind, IASTExpression lhs, IContainerSymbol startingScope) throws ASTSemanticException{
if((kind == IASTExpression.Kind.POSTFIX_DOT_IDEXPRESSION) if( kind.isPostfixMemberReference() )
|| (kind == IASTExpression.Kind.POSTFIX_ARROW_IDEXPRESSION) {
|| (kind == IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS)
|| (kind == IASTExpression.Kind.POSTFIX_ARROW_TEMPL_IDEXP)
|| (kind == IASTExpression.Kind.PM_DOTSTAR)
|| (kind == IASTExpression.Kind.PM_ARROWSTAR)
){
TypeInfo lhsInfo = ((ASTExpression)lhs).getResultType().getResult(); TypeInfo lhsInfo = ((ASTExpression)lhs).getResultType().getResult();
if(lhsInfo != null){ if(lhsInfo != null){
TypeInfo info = null; TypeInfo info = null;
@ -3166,6 +3161,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
} }
protected ParserSymbolTable pst; protected ParserSymbolTable pst;
protected static final List DUD_LIST = new ArrayList( 64 );
/* /*
@ -3426,6 +3422,40 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
} catch (ASTSemanticException e1) { } catch (ASTSemanticException e1) {
} }
} }
else if( expression.getExpressionKind() == IASTExpression.Kind.NEW_NEWTYPEID ||
expression.getExpressionKind() == IASTExpression.Kind.NEW_TYPEID )
{
IContainerSymbol classSymbol = null;
try {
classSymbol = (IContainerSymbol) lookupQualifiedName(scopeToSymbol( scope ), duple, DUD_LIST, false );
} catch (ASTSemanticException e) {
}
if( classSymbol != null && classSymbol.getTypeInfo().checkBit( TypeInfo.isTypedef ) ){
TypeInfo info = classSymbol.getTypeInfo().getFinalType();
classSymbol = (IContainerSymbol) info.getTypeSymbol();
}
if( classSymbol == null || ! (classSymbol instanceof IDerivableContainerSymbol ) ){
return null;
}
List parameters = new LinkedList();
Iterator newInitializerExpressions = expression.getNewExpressionDescriptor().getNewInitializerExpressions();
if( newInitializerExpressions.hasNext() )
{
ASTExpression expressionList = (ASTExpression) newInitializerExpressions.next();
while( expressionList != null ){
parameters.add( expressionList.getResultType().getResult() );
expressionList = (ASTExpression) expressionList.getRHSExpression();
}
}
try {
s = ((IDerivableContainerSymbol)classSymbol).lookupConstructor( parameters );
} catch (ParserSymbolTableException e1) {
return null;
}
}
else else
{ {
ASTExpression ownerExpression = expression.findOwnerExpressionForIDExpression( duple ); ASTExpression ownerExpression = expression.findOwnerExpressionForIDExpression( duple );
@ -3540,4 +3570,12 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
expression.setResultType (expressionResult); expression.setResultType (expressionResult);
return expression; return expression;
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.ast.IASTFactory#lookupConstructor(org.eclipse.cdt.core.parser.ast.IASTScope, org.eclipse.cdt.core.parser.ast.IASTExpression.IASTNewExpressionDescriptor)
*/
public IASTNode lookupConstructor(IASTScope ourScope, IASTNewExpressionDescriptor newDescriptor) {
// TODO Auto-generated method stub
return null;
}
} }

View file

@ -914,5 +914,12 @@ public class ExpressionParseASTFactory extends BaseASTFactory implements IASTFac
return ExpressionFactory.createExpression( kind, literal, isHex ); return ExpressionFactory.createExpression( kind, literal, isHex );
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.ast.IASTFactory#lookupConstructor(org.eclipse.cdt.core.parser.ast.IASTScope, org.eclipse.cdt.core.parser.ITokenDuple)
*/
public IASTNode lookupConstructor(IASTScope ourScope, IASTNewExpressionDescriptor newDescriptor) {
return null;
}
} }

View file

@ -13,6 +13,8 @@ package org.eclipse.cdt.internal.core.parser.ast.quick;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.cdt.core.parser.ISourceElementRequestor; import org.eclipse.cdt.core.parser.ISourceElementRequestor;
import org.eclipse.cdt.core.parser.ITokenDuple;
import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
import org.eclipse.cdt.core.parser.ast.IASTExpression; import org.eclipse.cdt.core.parser.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ast.IASTInitializerClause; import org.eclipse.cdt.core.parser.ast.IASTInitializerClause;
import org.eclipse.cdt.core.parser.ast.IASTVariable; import org.eclipse.cdt.core.parser.ast.IASTVariable;
@ -100,4 +102,11 @@ public class ASTInitializerClause implements IASTInitializerClause {
return ownerDeclaration; return ownerDeclaration;
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.ast.IASTInitializerClause#findExpressionForDuple(org.eclipse.cdt.core.parser.ITokenDuple)
*/
public IASTExpression findExpressionForDuple(ITokenDuple finalDuple) throws ASTNotImplementedException {
throw new ASTNotImplementedException();
}
} }

View file

@ -390,4 +390,11 @@ public class QuickParseASTFactory extends BaseASTFactory implements IASTFactory
public IASTExpression createExpression(Kind kind, long literal, boolean isHex) throws ASTSemanticException { public IASTExpression createExpression(Kind kind, long literal, boolean isHex) throws ASTSemanticException {
return ExpressionFactory.createExpression(kind, literal, isHex ); return ExpressionFactory.createExpression(kind, literal, isHex );
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.core.parser.ast.IASTFactory#lookupConstructor(org.eclipse.cdt.core.parser.ast.IASTScope, org.eclipse.cdt.core.parser.ITokenDuple)
*/
public IASTNode lookupConstructor(IASTScope ourScope, IASTNewExpressionDescriptor newDescriptor) {
return null;
}
} }