1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-28 19:35:36 +02:00

Initial support for prefix lookup in C++ ( used in content assist )

This commit is contained in:
Andrew Niefer 2005-02-21 21:41:51 +00:00
parent 4ab007930b
commit 790e164442
2 changed files with 165 additions and 39 deletions

View file

@ -1898,5 +1898,29 @@ public class AST2CPPTests extends AST2BaseTest {
IVariable g = (IVariable) col.getName(3).resolveBinding(); IVariable g = (IVariable) col.getName(3).resolveBinding();
assertInstances( col, g, 3 ); assertInstances( col, g, 3 );
} }
public void testPrefixLookup() throws Exception {
StringBuffer buffer = new StringBuffer();
buffer.append( "struct A { \n"); //$NON-NLS-1$
buffer.append( " int a2; \n"); //$NON-NLS-1$
buffer.append( "}; \n"); //$NON-NLS-1$
buffer.append( "struct B : public A { \n"); //$NON-NLS-1$
buffer.append( " int a1; \n"); //$NON-NLS-1$
buffer.append( " void f(); \n"); //$NON-NLS-1$
buffer.append( "} \n"); //$NON-NLS-1$
buffer.append( "int a3; \n"); //$NON-NLS-1$
buffer.append( "void B::f(){ \n"); //$NON-NLS-1$
buffer.append( " int a4; \n"); //$NON-NLS-1$
buffer.append( " a; \n"); //$NON-NLS-1$
buffer.append( "} \n"); //$NON-NLS-1$
IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP);
CPPNameCollector col = new CPPNameCollector();
CPPVisitor.visitTranslationUnit(tu, col);
IASTName name = col.getName(11);
IBinding [] bs = CPPSemantics.prefixLookup( name );
assertEquals( 4, bs.length );
}
} }

View file

@ -89,6 +89,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.parser.ast.IASTNamespaceDefinition; import org.eclipse.cdt.core.parser.ast.IASTNamespaceDefinition;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.ObjectMap; import org.eclipse.cdt.core.parser.util.ObjectMap;
import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.core.parser.util.ObjectSet;
@ -118,11 +119,14 @@ public class CPPSemantics {
public boolean ignoreUsingDirectives = false; public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false; public boolean usingDirectivesOnly = false;
public boolean forceQualified = false; public boolean forceQualified = false;
public Object [] foundItems = null; public boolean forUserDefinedConversion = false;
public boolean forAssociatedScopes = false;
public boolean prefixLookup = false;
public Object foundItems = null;
public Object [] functionParameters; public Object [] functionParameters;
public boolean forUserDefinedConversion; public ProblemBinding problem;
public ProblemBinding problem;
public boolean forAssociatedScopes = false;
public LookupData( IASTName n ){ public LookupData( IASTName n ){
astName = n; astName = n;
@ -216,6 +220,15 @@ public class CPPSemantics {
} }
return false; return false;
} }
public boolean hasResults(){
if( foundItems == null )
return false;
if( foundItems instanceof Object [] )
return ((Object[])foundItems).length != 0;
if( foundItems instanceof CharArrayObjectMap )
return ((CharArrayObjectMap)foundItems).size() != 0;
return false;
}
} }
static protected class Cost static protected class Cost
@ -549,7 +562,46 @@ public class CPPSemantics {
} }
return (ICPPScope) CPPVisitor.getContainingScope( name ); return (ICPPScope) CPPVisitor.getContainingScope( name );
} }
private static void mergeResults( LookupData data, Object results, boolean scoped ){
if( !data.prefixLookup ){
if( results instanceof IBinding ){
data.foundItems = ArrayUtil.append( Object.class, (Object[]) data.foundItems, results );
} else if( results instanceof Object[] ){
data.foundItems = ArrayUtil.addAll( Object.class, (Object[])data.foundItems, (Object[])results );
}
} else {
Object [] objs = (Object[]) results;
CharArrayObjectMap resultMap = (CharArrayObjectMap) data.foundItems;
if( objs != null ) {
for( int i = 0; i < objs.length && objs[i] != null; i++ ){
char [] n = null;
if( objs[i] instanceof IBinding )
n = ((IBinding)objs[i]).getNameCharArray();
else
n = ((IASTName)objs[i]).toCharArray();
if( !resultMap.containsKey( n ) ){
resultMap.put( n, objs[i] );
} else if( !scoped ) {
Object obj = resultMap.get( n );
if( obj instanceof Object [] ) {
if( objs[i] instanceof IBinding )
obj = ArrayUtil.append( Object.class, (Object[]) obj, objs[i] );
else
obj = ArrayUtil.addAll( Object.class, (Object[])obj, (Object[]) objs[i] );
} else {
if( objs[i] instanceof IBinding )
obj = new Object [] { obj, objs[i] };
else {
Object [] temp = new Object [ ((Object[])objs[i]).length + 1 ];
temp[0] = obj;
obj = ArrayUtil.addAll( Object.class, temp, (Object[]) objs[i] );
}
}
}
}
}
}
}
static private void lookup( CPPSemantics.LookupData data, Object start ) throws DOMException{ static private void lookup( CPPSemantics.LookupData data, Object start ) throws DOMException{
IASTNode node = data.astName; IASTNode node = data.astName;
@ -566,19 +618,18 @@ public class CPPSemantics {
ArrayWrapper directives = null; ArrayWrapper directives = null;
if( !data.usingDirectivesOnly ){ if( !data.usingDirectivesOnly ){
IBinding binding = scope.getBinding( data.astName ); IBinding binding = data.prefixLookup ? null : scope.getBinding( data.astName );
if( binding == null ){ if( binding == null ){
directives = new ArrayWrapper(); directives = new ArrayWrapper();
data.foundItems = lookupInScope( data, scope, blockItem, directives ); mergeResults( data, lookupInScope( data, scope, blockItem, directives ), true );
} else { } else {
data.foundItems = ArrayUtil.append( Object.class, data.foundItems, binding ); mergeResults( data, binding, true );
} }
} }
if( !data.ignoreUsingDirectives ) { if( !data.ignoreUsingDirectives ) {
data.visited.clear(); data.visited.clear();
if( data.foundItems == null || data.foundItems.length == 0 ){ if( data.prefixLookup || !data.hasResults() ){
Object[] transitives = lookupInNominated( data, scope, null ); Object[] transitives = lookupInNominated( data, scope, null );
processDirectives( data, scope, transitives ); processDirectives( data, scope, transitives );
@ -588,21 +639,21 @@ public class CPPSemantics {
while( !data.usingDirectives.isEmpty() && data.usingDirectives.get( scope ) != null ){ while( !data.usingDirectives.isEmpty() && data.usingDirectives.get( scope ) != null ){
transitives = lookupInNominated( data, scope, transitives ); transitives = lookupInNominated( data, scope, transitives );
if( !data.qualified() || data.foundItems == null ){ if( !data.qualified() || ( data.prefixLookup || !data.hasResults()) ){
processDirectives( data, scope, transitives ); processDirectives( data, scope, transitives );
} }
} }
} }
} }
if( data.problem != null || data.foundItems != null && data.foundItems.length != 0 ) if( !data.prefixLookup && (data.problem != null || data.hasResults()) )
return; return;
if( !data.usingDirectivesOnly && scope instanceof ICPPClassScope ){ if( !data.usingDirectivesOnly && scope instanceof ICPPClassScope ){
data.foundItems = lookupInParents( data, (ICPPClassScope) scope ); mergeResults( data, lookupInParents( data, (ICPPClassScope) scope ), true );
} }
if( data.problem != null || data.foundItems != null && data.foundItems.length != 0 ) if( !data.prefixLookup && (data.problem != null || data.hasResults()) )
return; return;
//if still not found, loop and check our containing scope //if still not found, loop and check our containing scope
@ -888,11 +939,8 @@ public class CPPSemantics {
} }
data.visited.put( temp ); data.visited.put( temp );
ArrayWrapper usings = new ArrayWrapper(); ArrayWrapper usings = new ArrayWrapper();
Object[] found = lookupInScope( data, temp, null, usings ); IASTName[] found = lookupInScope( data, temp, null, usings );
if( data.foundItems == null ) mergeResults( data, found, false );
data.foundItems = found;
else if( found != null )
data.foundItems = ArrayUtil.addAll( Object.class, data.foundItems, found );
//only consider the transitive using directives if we are an unqualified //only consider the transitive using directives if we are an unqualified
//lookup, or we didn't find the name in decl //lookup, or we didn't find the name in decl
@ -918,9 +966,9 @@ public class CPPSemantics {
while( dtor.getNestedDeclarator() != null ) while( dtor.getNestedDeclarator() != null )
dtor = dtor.getNestedDeclarator(); dtor = dtor.getNestedDeclarator();
IASTName declName = dtor.getName(); IASTName declName = dtor.getName();
if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ if( nameMatches( data, declName.toCharArray() ) ) {
return declName; return declName;
} }
} }
if( declaration == null ) if( declaration == null )
return null; return null;
@ -935,7 +983,7 @@ public class CPPSemantics {
declarator = declarator.getNestedDeclarator(); declarator = declarator.getNestedDeclarator();
if( data.considerConstructors() || !CPPVisitor.isConstructor( scope, declarator ) ){ if( data.considerConstructors() || !CPPVisitor.isConstructor( scope, declarator ) ){
IASTName declaratorName = declarator.getName(); IASTName declaratorName = declarator.getName();
if( CharArrayUtils.equals( declaratorName.toCharArray(), data.name ) ){ if( nameMatches( data, declaratorName.toCharArray() ) ) {
return declaratorName; return declaratorName;
} }
} }
@ -946,18 +994,18 @@ public class CPPSemantics {
IASTDeclSpecifier declSpec = simpleDeclaration.getDeclSpecifier(); IASTDeclSpecifier declSpec = simpleDeclaration.getDeclSpecifier();
if( declSpec instanceof IASTElaboratedTypeSpecifier ){ if( declSpec instanceof IASTElaboratedTypeSpecifier ){
IASTName elabName = ((IASTElaboratedTypeSpecifier)declSpec).getName(); IASTName elabName = ((IASTElaboratedTypeSpecifier)declSpec).getName();
if( CharArrayUtils.equals( elabName.toCharArray(), data.name ) ){ if( nameMatches( data, elabName.toCharArray() ) ) {
return elabName; return elabName;
} }
} else if( declSpec instanceof ICPPASTCompositeTypeSpecifier ){ } else if( declSpec instanceof ICPPASTCompositeTypeSpecifier ){
IASTName compName = ((IASTCompositeTypeSpecifier)declSpec).getName(); IASTName compName = ((IASTCompositeTypeSpecifier)declSpec).getName();
if( CharArrayUtils.equals( compName.toCharArray(), data.name ) ){ if( nameMatches( data, compName.toCharArray() ) ) {
return compName; return compName;
} }
} else if( declSpec instanceof IASTEnumerationSpecifier ){ } else if( declSpec instanceof IASTEnumerationSpecifier ){
IASTEnumerationSpecifier enumeration = (IASTEnumerationSpecifier) declSpec; IASTEnumerationSpecifier enumeration = (IASTEnumerationSpecifier) declSpec;
IASTName eName = enumeration.getName(); IASTName eName = enumeration.getName();
if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ if( nameMatches( data, eName.toCharArray() ) ) {
return eName; return eName;
} }
if( !data.typesOnly() ) { if( !data.typesOnly() ) {
@ -967,7 +1015,7 @@ public class CPPSemantics {
IASTEnumerator enumerator = list[i]; IASTEnumerator enumerator = list[i];
if( enumerator == null ) break; if( enumerator == null ) break;
eName = enumerator.getName(); eName = enumerator.getName();
if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ if( nameMatches( data, eName.toCharArray() ) ) {
return eName; return eName;
} }
} }
@ -980,16 +1028,16 @@ public class CPPSemantics {
IASTName [] ns = ((ICPPASTQualifiedName)name).getNames(); IASTName [] ns = ((ICPPASTQualifiedName)name).getNames();
name = ns[ ns.length - 1 ]; name = ns[ ns.length - 1 ];
} }
if( CharArrayUtils.equals( name.toCharArray(), data.name ) ){ if( nameMatches( data, name.toCharArray() ) ) {
return name; return name;
} }
} else if( declaration instanceof ICPPASTNamespaceDefinition ){ } else if( declaration instanceof ICPPASTNamespaceDefinition ){
IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName(); IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName();
if( CharArrayUtils.equals( namespaceName.toCharArray(), data.name ) ) if( nameMatches( data, namespaceName.toCharArray() ) )
return namespaceName; return namespaceName;
} else if( declaration instanceof ICPPASTNamespaceAlias ){ } else if( declaration instanceof ICPPASTNamespaceAlias ){
IASTName alias = ((ICPPASTNamespaceAlias) declaration).getAlias(); IASTName alias = ((ICPPASTNamespaceAlias) declaration).getAlias();
if( CharArrayUtils.equals( alias.toCharArray(), data.name ) ) if( nameMatches( data, alias.toCharArray() ) )
return alias; return alias;
} }
@ -1003,7 +1051,7 @@ public class CPPSemantics {
//check the function itself //check the function itself
IASTName declName = declarator.getName(); IASTName declName = declarator.getName();
if( data.considerConstructors() || !CPPVisitor.isConstructor( scope, declarator ) ){ if( data.considerConstructors() || !CPPVisitor.isConstructor( scope, declarator ) ){
if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ if( nameMatches( data, declName.toCharArray() ) ) {
return declName; return declName;
} }
} }
@ -1018,7 +1066,7 @@ public class CPPSemantics {
while( dtor.getNestedDeclarator() != null ) while( dtor.getNestedDeclarator() != null )
dtor = dtor.getNestedDeclarator(); dtor = dtor.getNestedDeclarator();
declName = dtor.getName(); declName = dtor.getName();
if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ if( nameMatches( data, declName.toCharArray() ) ) {
return declName; return declName;
} }
} }
@ -1029,6 +1077,11 @@ public class CPPSemantics {
return null; return null;
} }
private static final boolean nameMatches( LookupData data, char[] potential ){
return ( (data.prefixLookup && CharArrayUtils.equals( potential, 0, data.name.length, data.name )) ||
(!data.prefixLookup && CharArrayUtils.equals( potential, data.name )) );
}
private static void addDefinition( IBinding binding, IASTName name ){ private static void addDefinition( IBinding binding, IASTName name ){
if( binding instanceof IFunction ){ if( binding instanceof IFunction ){
IASTNode node = name.getParent(); IASTNode node = name.getParent();
@ -1071,7 +1124,7 @@ public class CPPSemantics {
} }
static private IBinding resolveAmbiguities( CPPSemantics.LookupData data, IASTName name ) throws DOMException { static private IBinding resolveAmbiguities( CPPSemantics.LookupData data, IASTName name ) throws DOMException {
if( data.foundItems == null || data.foundItems.length == 0 ) if( !data.hasResults() || data.prefixLookup )
return null; return null;
IBinding type = null; IBinding type = null;
@ -1079,8 +1132,9 @@ public class CPPSemantics {
IBinding temp = null; IBinding temp = null;
IFunction[] fns = null; IFunction[] fns = null;
for( int i = 0; i < data.foundItems.length && data.foundItems[i] != null; i++ ){ Object [] items = (Object[]) data.foundItems;
Object o = data.foundItems[i]; for( int i = 0; i < items.length && items[i] != null; i++ ){
Object o = items[i];
if( o instanceof IASTName ) if( o instanceof IASTName )
temp = ((IASTName) o).resolveBinding(); temp = ((IASTName) o).resolveBinding();
else if( o instanceof IBinding ){ else if( o instanceof IBinding ){
@ -1092,7 +1146,8 @@ public class CPPSemantics {
if( temp instanceof ICPPCompositeBinding ){ if( temp instanceof ICPPCompositeBinding ){
IBinding [] bindings = ((ICPPCompositeBinding) temp).getBindings(); IBinding [] bindings = ((ICPPCompositeBinding) temp).getBindings();
data.foundItems = ArrayUtil.addAll( Object.class, data.foundItems, bindings ); //data.foundItems = ArrayUtil.addAll( Object.class, data.foundItems, bindings );
mergeResults( data, bindings, false );
continue; continue;
} else if( temp instanceof IType ){ } else if( temp instanceof IType ){
if( type == null ){ if( type == null ){
@ -1587,10 +1642,11 @@ public class CPPSemantics {
} catch ( DOMException e1 ) { } catch ( DOMException e1 ) {
return null; return null;
} }
if( data.foundItems != null && data.foundItems.length > 0 ){ if( data.hasResults() ){
Object [] items = (Object[]) data.foundItems;
IBinding temp = null; IBinding temp = null;
for( int i = 0; i < data.foundItems.length; i++ ){ for( int i = 0; i < items.length; i++ ){
Object o = data.foundItems[i]; Object o = items[i];
if( o == null ) break; if( o == null ) break;
if( o instanceof IASTName ) if( o instanceof IASTName )
temp = ((IASTName) o).resolveBinding(); temp = ((IASTName) o).resolveBinding();
@ -2056,4 +2112,50 @@ public class CPPSemantics {
return binding; return binding;
} }
public static IBinding [] prefixLookup( IASTName name ){
LookupData data = createLookupData( name, true );
data.prefixLookup = true;
data.foundItems = new CharArrayObjectMap( 2 );
try {
lookup( data, name );
} catch ( DOMException e ) {
}
CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems;
IBinding [] result = null;
if( !map.isEmpty() ){
char [] key = null;
Object obj = null;
int size = map.size();
for( int i = 0; i < size; i++ ) {
key = map.keyAt( i );
obj = map.get( key );
if( obj instanceof IBinding )
result = (IBinding[]) ArrayUtil.append( IBinding.class, result, obj );
else {
Object item = null;
if( obj instanceof Object[] ){
Object[] objs = (Object[]) obj;
if( objs.length > 1 && objs[1] != null )
continue;
item = objs[0];
} else {
item = obj;
}
if( item instanceof IBinding )
result = (IBinding[]) ArrayUtil.append( IBinding.class, result, item );
else {
IBinding binding = ((IASTName) item).resolveBinding();
if( binding != null && !(binding instanceof IProblemBinding))
result = (IBinding[]) ArrayUtil.append( IBinding.class, result, binding );
}
}
}
}
return (IBinding[]) ArrayUtil.trim( IBinding.class, result );
}
} }