1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

Symbol Table work for Content Assist By Andrew

This commit is contained in:
Hoda Amer 2003-12-17 20:51:39 +00:00
parent 33f033599d
commit 67ad10a37b
14 changed files with 275 additions and 43 deletions

View file

@ -1,3 +1,10 @@
2003-12-17 Andrew Niefer
test changes for content assist
added ContextualParseTest.testCompletionLookup_FriendClass_1()
added ContextualParseTest.testCompletionLookup_FriendClass_2()
added ContextualParseTest.testCompletionLookup_ParametersAsLocalVariables()
modified ParserSymbolTableTest.testVisibilityDetermination()
2003-12-17 Hoda Amer
Small modifications to cope with the new interfaces

View file

@ -17,11 +17,13 @@ import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.ScannerInfo;
import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTCodeScope;
import org.eclipse.cdt.core.parser.ast.IASTCompletionNode;
import org.eclipse.cdt.core.parser.ast.IASTField;
import org.eclipse.cdt.core.parser.ast.IASTFunction;
import org.eclipse.cdt.core.parser.ast.IASTMethod;
import org.eclipse.cdt.core.parser.ast.IASTNode;
import org.eclipse.cdt.core.parser.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.parser.ast.IASTVariable;
import org.eclipse.cdt.core.parser.ast.IASTNode.LookupResult;
import org.eclipse.cdt.internal.core.parser.ParserLogService;
@ -246,4 +248,127 @@ public class ContextualParseTest extends CompleteParseBaseTest {
assertEquals( method.getName(), "aMethod" );
assertEquals( baseMethod.getName(), "aPublicBaseMethod" );
}
public void testCompletionLookup_FriendClass_1() throws Exception{
StringWriter writer = new StringWriter();
writer.write( "class A {" );
writer.write( " private: void aPrivateMethod();" );
writer.write( " friend class C;" );
writer.write( "};" );
writer.write( "class C {" );
writer.write( " void foo();" );
writer.write( "};" );
writer.write( "void C::foo(){" );
writer.write( " A a;" );
writer.write( " a.a \n" );
String code = writer.toString();
int index = code.indexOf( "a.a" );
IASTCompletionNode node = parse( code, index + 3 );
assertNotNull( node );
String prefix = node.getCompletionPrefix();
assertEquals( prefix, "a" );
assertTrue( node.getCompletionScope() instanceof IASTFunction );
assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE );
assertNotNull( node.getCompletionContext() );
assertTrue( node.getCompletionContext() instanceof IASTClassSpecifier );
LookupResult result = node.getCompletionScope().lookup( prefix, new IASTNode.LookupKind [] { IASTNode.LookupKind.METHODS }, node.getCompletionContext() );
assertEquals( result.getPrefix(), prefix );
Iterator iter = result.getNodes();
assertTrue( iter.hasNext() );
IASTMethod method = (IASTMethod) iter.next();
assertFalse( iter.hasNext() );
assertEquals( method.getName(), "aPrivateMethod" );
}
public void testCompletionLookup_FriendClass_2() throws Exception{
StringWriter writer = new StringWriter();
writer.write( "class C {" );
writer.write( " void foo();" );
writer.write( "};" );
writer.write( "class A {" );
writer.write( " private: void aPrivateMethod();" );
writer.write( " friend class C;" );
writer.write( "};" );
writer.write( "void C::foo(){" );
writer.write( " A a;" );
writer.write( " a.a \n" );
String code = writer.toString();
int index = code.indexOf( "a.a" );
IASTCompletionNode node = parse( code, index + 3 );
assertNotNull( node );
String prefix = node.getCompletionPrefix();
assertEquals( prefix, "a" );
assertTrue( node.getCompletionScope() instanceof IASTFunction );
assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE );
assertNotNull( node.getCompletionContext() );
assertTrue( node.getCompletionContext() instanceof IASTClassSpecifier );
LookupResult result = node.getCompletionScope().lookup( prefix, new IASTNode.LookupKind [] { IASTNode.LookupKind.METHODS }, node.getCompletionContext() );
assertEquals( result.getPrefix(), prefix );
Iterator iter = result.getNodes();
assertTrue( iter.hasNext() );
IASTMethod method = (IASTMethod) iter.next();
assertFalse( iter.hasNext() );
assertEquals( method.getName(), "aPrivateMethod" );
}
public void testCompletionLookup_ParametersAsLocalVariables() throws Exception{
StringWriter writer = new StringWriter();
writer.write( "int foo( int aParameter ){" );
writer.write( " int aLocal;" );
writer.write( " if( aLocal != 0 ){" );
writer.write( " int aBlockLocal;" );
writer.write( " a \n" );
String code = writer.toString();
int index = code.indexOf( " a " );
IASTCompletionNode node = parse( code, index + 2 );
assertNotNull( node );
String prefix = node.getCompletionPrefix();
assertEquals( prefix, "a" );
assertTrue( node.getCompletionScope() instanceof IASTCodeScope );
assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.SINGLE_NAME_REFERENCE );
assertNull( node.getCompletionContext() );
LookupResult result = node.getCompletionScope().lookup( prefix, new IASTNode.LookupKind [] { IASTNode.LookupKind.LOCAL_VARIABLES }, node.getCompletionContext() );
assertEquals( result.getPrefix(), prefix );
Iterator iter = result.getNodes();
IASTVariable aBlockLocal = (IASTVariable) iter.next();
IASTVariable aLocal = (IASTVariable) iter.next();
IASTParameterDeclaration aParameter = (IASTParameterDeclaration) iter.next();
assertFalse( iter.hasNext() );
assertEquals( aBlockLocal.getName(), "aBlockLocal" );
assertEquals( aLocal.getName(), "aLocal" );
assertEquals( aParameter.getName(), "aParameter" );
}
}

View file

@ -3209,20 +3209,36 @@ public class ParserSymbolTableTest extends TestCase {
}
/**
* class A { public: static int i; };
* class D { };
* class A {
* public: static int i;
* private: static int j;
* friend class D;
* };
* class B : private A {};
* class C : public B, public A {};
*
*
* @throws Exception
*/
public void testVisibilityDetermination() throws Exception{
newTable();
IDerivableContainerSymbol D = table.newDerivableContainerSymbol( "D", TypeInfo.t_class );
table.getCompilationUnit().addSymbol( D );
IDerivableContainerSymbol A = table.newDerivableContainerSymbol( "A", TypeInfo.t_class );
ISymbol i = table.newSymbol( "i", TypeInfo.t_int );
ISymbol j = table.newSymbol( "j", TypeInfo.t_int );
table.getCompilationUnit().addSymbol( A );
ISymbol friend = A.lookupForFriendship( "D" );
assertEquals( friend, D );
A.addFriend( friend );
A.addSymbol( i );
A.addSymbol( j );
IASTCompilationUnit compUnit = new ASTCompilationUnit(table.getCompilationUnit() );
ISymbolASTExtension cuExtension = new StandardSymbolExtension( table.getCompilationUnit(), (ASTSymbol) compUnit );
@ -3235,6 +3251,10 @@ public class ParserSymbolTableTest extends TestCase {
IASTField field = new ASTField(i, null, null, null, 0, 0, 0, new ArrayList(), false, null, ASTAccessVisibility.PUBLIC );
ISymbolASTExtension extension = new StandardSymbolExtension( i, (ASTSymbol) field );
i.setASTExtension( extension );
field = new ASTField(i, null, null, null, 0, 0, 0, new ArrayList(), false, null, ASTAccessVisibility.PRIVATE );
extension = new StandardSymbolExtension( j, (ASTSymbol) field );
j.setASTExtension( extension );
IDerivableContainerSymbol B = table.newDerivableContainerSymbol( "B", TypeInfo.t_class );
B.addParent( A, false, ASTAccessVisibility.PRIVATE, 0, null );
@ -3248,6 +3268,8 @@ public class ParserSymbolTableTest extends TestCase {
assertTrue( table.getCompilationUnit().isVisible( i, A ) );
assertFalse( table.getCompilationUnit().isVisible( i, B ) );
assertTrue( table.getCompilationUnit().isVisible(i, C ) );
assertTrue( D.isVisible( j, A ) );
assertFalse( D.isVisible( j, B ) );
}
/**

View file

@ -1,3 +1,9 @@
2003-12-17 Andrew Niefer
Content Assist work:
- change parser & symbol table to handle handle friend classes
- change visibility filtering to check for friendship
- fix finding function parameters in prefix lookup
2003-12-17 Hoda Amer
Content Assist work : Integrated with Parser and Symbol table modifications

View file

@ -97,7 +97,7 @@ public interface IASTFactory
IASTScope scope,
ASTClassKind elaboratedClassKind,
ITokenDuple typeName,
int startingOffset, int endOffset, boolean isForewardDecl) throws ASTSemanticException;
int startingOffset, int endOffset, boolean isForewardDecl, boolean isFriend) throws ASTSemanticException;
public IASTEnumerationSpecifier createEnumerationSpecifier(
IASTScope scope,

View file

@ -1654,7 +1654,7 @@ public abstract class Parser implements IParser
d,
t.getOffset(),
d.getLastToken().getEndOffset(),
isForewardDecl );
isForewardDecl, sdw.isFriend() );
}
catch (ASTSemanticException e)
{

View file

@ -2485,7 +2485,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
}
public IASTElaboratedTypeSpecifier createElaboratedTypeSpecifier(IASTScope scope, ASTClassKind kind, ITokenDuple name, int startingOffset, int endOffset, boolean isForewardDecl) throws ASTSemanticException
public IASTElaboratedTypeSpecifier createElaboratedTypeSpecifier(IASTScope scope, ASTClassKind kind, ITokenDuple name, int startingOffset, int endOffset, boolean isForewardDecl, boolean isFriend) throws ASTSemanticException
{
IContainerSymbol currentScopeSymbol = scopeToSymbol(scope);
TypeInfo.eType pstType = classKindToTypeInfo(kind);
@ -2504,7 +2504,14 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
ISymbol checkSymbol = null;
try
{
checkSymbol = currentScopeSymbol.elaboratedLookup( pstType, lastToken.getImage());
if( isFriend ){
if( !(currentScopeSymbol instanceof IDerivableContainerSymbol) ){
throw new ASTSemanticException();
}
checkSymbol = ((IDerivableContainerSymbol)currentScopeSymbol).lookupForFriendship( lastToken.getImage() );
} else {
checkSymbol = currentScopeSymbol.elaboratedLookup( pstType, lastToken.getImage());
}
}
catch (ParserSymbolTableException e)
{
@ -2520,7 +2527,11 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
checkSymbol.setIsForwardDeclaration( true );
try
{
currentScopeSymbol.addSymbol( checkSymbol );
if( isFriend ){
((IDerivableContainerSymbol)currentScopeSymbol).addFriend( checkSymbol );
} else {
currentScopeSymbol.addSymbol( checkSymbol );
}
}
catch (ParserSymbolTableException e1)
{
@ -2538,6 +2549,13 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
{
throw new ASTSemanticException();
}
} else if( isFriend ){
try {
((IDerivableContainerSymbol)currentScopeSymbol).addFriend( checkSymbol );
} catch (ParserSymbolTableException e1) {
throw new ASTSemanticException();
}
}
}
@ -2612,7 +2630,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto
public IASTCodeScope createNewCodeBlock(IASTScope scope) {
IContainerSymbol symbol = scopeToSymbol( scope );
IContainerSymbol newScope = pst.newContainerSymbol("");
IContainerSymbol newScope = pst.newContainerSymbol("", TypeInfo.t_block);
newScope.setContainingSymbol(symbol);
ASTCodeScope codeScope = new ASTCodeScope( newScope );

View file

@ -263,7 +263,7 @@ public class QuickParseASTFactory extends BaseASTFactory implements IASTFactory
return new ASTAbstractTypeSpecifierDeclaration( scope, typeSpecifier, template, startingOffset, endingOffset );
}
public IASTElaboratedTypeSpecifier createElaboratedTypeSpecifier(IASTScope scope, ASTClassKind elaboratedClassKind, ITokenDuple typeName, int startingOffset, int endOffset, boolean isForewardDecl)
public IASTElaboratedTypeSpecifier createElaboratedTypeSpecifier(IASTScope scope, ASTClassKind elaboratedClassKind, ITokenDuple typeName, int startingOffset, int endOffset, boolean isForewardDecl, boolean isFriend)
{
return new ASTElaboratedTypeSpecifier( scope, elaboratedClassKind, typeName.toString(), startingOffset, typeName.getFirstToken().getOffset(), typeName.getLastToken().getEndOffset(), endOffset );
}

View file

@ -169,12 +169,21 @@ public class BasicSymbol implements Cloneable, ISymbol
public Map getArgumentMap(){
return null;
}
public boolean getIsInvisible(){
return _isInvisible;
}
public void setIsInvisible( boolean invisible ){
_isInvisible = invisible ;
}
private String _name; //our name
private ISymbolASTExtension _object; //the object associated with us
private TypeInfo _typeInfo; //our type info
private IContainerSymbol _containingScope; //the scope that contains us
private int _depth; //how far down the scope stack we are
private boolean _isInvisible = false; //used by friend declarations (11.4-9)
private boolean _isTemplateMember = false;
private TemplateInstance _templateInstance;
}

View file

@ -635,8 +635,12 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol {
{
return true;
}
//if this is a friend of the symbolContainer, then we are good
if( isFriendOf( symbolContainer ) ){
return true;
}
//TODO: friendship
if( visibility == ASTAccessVisibility.PROTECTED )
{
try {
@ -651,6 +655,33 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol {
return true;
}
protected boolean isFriendOf( IContainerSymbol symbol ){
if( symbol instanceof IDerivableContainerSymbol ){
IContainerSymbol container = this.getContainingSymbol();
while( container != null && container.isType( TypeInfo.t_block ) ){
container = container.getContainingSymbol();
}
if( container != null && !container.isType( TypeInfo.t_class, TypeInfo.t_union ) ){
container = null;
}
IDerivableContainerSymbol derivable = (IDerivableContainerSymbol) symbol;
Iterator iter = derivable.getFriends().iterator();
while( iter.hasNext() ){
ISymbol friend = (ISymbol) iter.next();
ISymbol typeSymbol = friend.getTypeSymbol();
if( friend == this || typeSymbol == this ||
friend == container || ( container != null && typeSymbol == container ) )
{
return true;
}
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#instantiate(java.util.List)
*/

View file

@ -241,24 +241,22 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva
* TODO: if/when the parser symbol table starts caring about visibility
* (public/protected/private) we will need to do more to record friendship.
*/
private ISymbol addFriend( String name ) throws ParserSymbolTableException{
ISymbol friend = lookupForFriendship( name );
if( friend == null ){
friend = getSymbolTable().newSymbol( name );
friend.getTypeInfo().setIsForwardDeclaration( true );
IContainerSymbol containing = getContainingSymbol();
//find innermost enclosing namespace
while( containing != null && containing.getType() != TypeInfo.t_namespace ){
containing = containing.getContainingSymbol();
public void addFriend( ISymbol friend ) throws ParserSymbolTableException{
//is this symbol already in the table?
IContainerSymbol containing = friend.getContainingSymbol();
if( containing == null ){
//its not, it goes in the innermost enclosing namespace
IContainerSymbol enclosing = getContainingSymbol();
while( enclosing != null && !enclosing.isType( TypeInfo.t_namespace ) ){
enclosing = enclosing.getContainingSymbol();
}
IContainerSymbol namespace = ( containing == null ) ? getSymbolTable().getCompilationUnit() : containing;
namespace.addSymbol( friend );
friend.setIsInvisible( true );
friend.setIsForwardDeclaration( true );
enclosing.addSymbol( friend );
}
return friend;
getFriends().add( friend );
}
/**
@ -273,24 +271,28 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva
* without considering scopes that are outside the innermost enclosing non-
* class scope.
*/
private ISymbol lookupForFriendship( String name ) throws ParserSymbolTableException{
public ISymbol lookupForFriendship( String name ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, TypeInfo.t_any, getTemplateInstance() );
boolean inClass = ( getType() == TypeInfo.t_class);
IContainerSymbol enclosing = getContainingSymbol();
while( enclosing != null && (inClass ? enclosing.getType() != TypeInfo.t_class
: enclosing.getType() == TypeInfo.t_namespace) )
{
enclosing = enclosing.getContainingSymbol();
if( enclosing != null && enclosing.isType( TypeInfo.t_namespace, TypeInfo.t_union ) ){
while( enclosing != null && ( enclosing.getType() != TypeInfo.t_namespace) )
{
enclosing = enclosing.getContainingSymbol();
}
}
data.stopAt = enclosing;
ParserSymbolTable.lookup( data, this );
return ParserSymbolTable.resolveAmbiguities( data );
}
public List getFriends(){
if( _friends == null ){
_friends = new LinkedList();
}
return _friends;
}
static private class AddParentCommand extends Command{
public AddParentCommand( IDerivableContainerSymbol container, ParentWrapper wrapper ){
@ -363,4 +365,5 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva
private LinkedList _constructors; //constructor list
private LinkedList _parentScopes; //inherited scopes (is base classes)
private LinkedList _friends;
}

View file

@ -38,6 +38,10 @@ public interface IDerivableContainerSymbol extends IContainerSymbol {
public IParameterizedSymbol lookupConstructor( List parameters ) throws ParserSymbolTableException;
public List getConstructors();
public void addFriend( ISymbol friend ) throws ParserSymbolTableException;
public ISymbol lookupForFriendship( String name ) throws ParserSymbolTableException;
public List getFriends();
public interface IParentSymbol{
public void setParent( ISymbol parent );
public ISymbol getParent();

View file

@ -54,6 +54,8 @@ public interface ISymbol extends Cloneable {
public void setTemplateInstance( TemplateInstance instance );
public int getDepth();
public boolean getIsInvisible();
public void setIsInvisible( boolean invisible );
/**
* @param name

View file

@ -335,7 +335,7 @@ public class ParserSymbolTable {
name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name;
while( name != null ){
if( nameMatches( data, name ) ){
obj = parameters.get( data.name );
obj = parameters.get( name );
obj = collectSymbol( data, obj );
if( obj != null ){
found.put( name, obj );
@ -393,7 +393,7 @@ public class ParserSymbolTable {
IContainerSymbol cls = null;
while( symbol != null ){
if( checkType( data, symbol ) ){//, data.type, data.upperType ) ){
if( !symbol.getIsInvisible() && checkType( data, symbol ) ){//, data.type, data.upperType ) ){
if( symbol.isTemplateMember() && data.templateInstance != null )
foundSymbol = new TemplateInstance( symbol.getSymbolTable(), symbol, data.templateInstance.getArgumentMap() );
else
@ -674,12 +674,17 @@ public class ParserSymbolTable {
TypeInfo.eType newType = newSymbol.getType();
//handle forward decls
if( origSymbol.getTypeInfo().isForwardDeclaration() &&
origSymbol.getTypeSymbol() == newSymbol )
{
return true;
if( origSymbol.getTypeInfo().isForwardDeclaration() ){
if( origSymbol.getTypeSymbol() == newSymbol )
return true;
//friend class declarations
if( origSymbol.getIsInvisible() && origSymbol.isType( newSymbol.getType() ) ){
origSymbol.getTypeInfo().setTypeSymbol( newSymbol );
return true;
}
}
if( (origType.compareTo(TypeInfo.t_class) >= 0 && origType.compareTo(TypeInfo.t_enumeration) <= 0) && //class name or enumeration ...
( newType == TypeInfo.t_type || (newType.compareTo( TypeInfo.t_function ) >= 0 /*&& newType <= TypeInfo.typeMask*/) ) ){
@ -707,7 +712,8 @@ public class ParserSymbolTable {
Iterator iter = origList.iterator();
ISymbol symbol = (ISymbol) iter.next();
boolean valid = ( (symbol.getType().compareTo( TypeInfo.t_class ) >= 0 ) && (symbol.getType().compareTo( TypeInfo.t_enumeration ) <= 0 ) );
boolean valid = isValidOverload( symbol, newSymbol );//( (symbol.getType().compareTo( TypeInfo.t_class ) >= 0 ) && (symbol.getType().compareTo( TypeInfo.t_enumeration ) <= 0 ) );
if( !valid && (symbol instanceof IParameterizedSymbol) )
valid = isValidFunctionOverload( (IParameterizedSymbol)symbol, (IParameterizedSymbol)newSymbol );
@ -2239,7 +2245,6 @@ public class ParserSymbolTable {
static protected class LookupData
{
public Set ambiguities;
public String name;
public Map usingDirectives;
@ -2256,7 +2261,7 @@ public class ParserSymbolTable {
public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false;
public boolean forUserDefinedConversion = false;
public Map foundItems = null;
public ISymbol templateInstance = null;