mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 10:16:03 +02:00
Argument dependent lookup aka Koenig lookup
This commit is contained in:
parent
11f48787a5
commit
8b9f51bf19
4 changed files with 165 additions and 24 deletions
|
@ -274,7 +274,7 @@ public class AST2BaseTest extends TestCase {
|
||||||
if( collector.getName( i ).resolveBinding() == binding )
|
if( collector.getName( i ).resolveBinding() == binding )
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
assertEquals( count, num );
|
assertEquals( num, count );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1310,5 +1310,61 @@ public class AST2CPPTests extends AST2BaseTest {
|
||||||
assertTrue( CharArrayUtils.equals( T.getNameCharArray(), "T".toCharArray() ) ) ; //$NON-NLS-1$
|
assertTrue( CharArrayUtils.equals( T.getNameCharArray(), "T".toCharArray() ) ) ; //$NON-NLS-1$
|
||||||
assertEquals( T.getName(), "T" ); //$NON-NLS-1$
|
assertEquals( T.getName(), "T" ); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testArgumentDependantLookup() throws Exception {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.append("namespace NS { \n"); //$NON-NLS-1$
|
||||||
|
buffer.append(" class T {}; \n"); //$NON-NLS-1$
|
||||||
|
buffer.append(" void f( T ); \n"); //$NON-NLS-1$
|
||||||
|
buffer.append("} \n"); //$NON-NLS-1$
|
||||||
|
buffer.append("NS::T parm; \n"); //$NON-NLS-1$
|
||||||
|
buffer.append("int main() { \n"); //$NON-NLS-1$
|
||||||
|
buffer.append(" f( parm ); \n"); //$NON-NLS-1$
|
||||||
|
buffer.append("} \n"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); //$NON-NLS-1$
|
||||||
|
CPPNameCollector col = new CPPNameCollector();
|
||||||
|
CPPVisitor.visitTranslationUnit(tu, col);
|
||||||
|
|
||||||
|
ICPPNamespace NS = (ICPPNamespace) col.getName(0).resolveBinding();
|
||||||
|
ICPPClassType T = (ICPPClassType) col.getName(1).resolveBinding();
|
||||||
|
IFunction f = (IFunction) col.getName(2).resolveBinding();
|
||||||
|
IVariable parm = (IVariable) col.getName(8).resolveBinding();
|
||||||
|
|
||||||
|
assertInstances( col, NS, 2 );
|
||||||
|
assertInstances( col, T, 4 );
|
||||||
|
assertInstances( col, f, 2 );
|
||||||
|
assertInstances( col, parm, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testArgumentDependantLookup_2() throws Exception {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.append("namespace NS1{ \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append(" void f( void * ); \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append("} \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append("namespace NS2{ \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append(" using namespace NS1; \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append(" class B {}; \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append(" void f( void * ); \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append("} \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append("class A : public NS2::B {} *a; \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append("int main() { \n" ); //$NON-NLS-1$
|
||||||
|
buffer.append(" f( 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);
|
||||||
|
|
||||||
|
IFunction fref = (IFunction) col.getName(14).resolveBinding();
|
||||||
|
IFunction f1 = (IFunction) col.getName(1).resolveBinding();
|
||||||
|
IFunction f2 = (IFunction) col.getName(6).resolveBinding();
|
||||||
|
|
||||||
|
assertSame( f2, fref );
|
||||||
|
assertNotNull( f1 );
|
||||||
|
assertNotNull( f2 );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
||||||
|
@ -106,9 +105,11 @@ public class CPPSemantics {
|
||||||
public ObjectMap usingDirectives = ObjectMap.EMPTY_MAP;
|
public ObjectMap usingDirectives = ObjectMap.EMPTY_MAP;
|
||||||
public ObjectSet visited = ObjectSet.EMPTY_SET; //used to ensure we don't visit things more than once
|
public ObjectSet visited = ObjectSet.EMPTY_SET; //used to ensure we don't visit things more than once
|
||||||
public ObjectSet inheritanceChain; //used to detect circular inheritance
|
public ObjectSet inheritanceChain; //used to detect circular inheritance
|
||||||
|
public ObjectSet associated = ObjectSet.EMPTY_SET;
|
||||||
|
|
||||||
public boolean ignoreUsingDirectives = false;
|
public boolean ignoreUsingDirectives = false;
|
||||||
public boolean usingDirectivesOnly = false;
|
public boolean usingDirectivesOnly = false;
|
||||||
|
public boolean forceQualified = false;
|
||||||
public List foundItems = null;
|
public List foundItems = null;
|
||||||
public Object [] functionParameters;
|
public Object [] functionParameters;
|
||||||
public boolean forUserDefinedConversion;
|
public boolean forUserDefinedConversion;
|
||||||
|
@ -176,6 +177,7 @@ public class CPPSemantics {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public boolean qualified(){
|
public boolean qualified(){
|
||||||
|
if( forceQualified ) return true;
|
||||||
if( astName == null ) return false;
|
if( astName == null ) return false;
|
||||||
IASTNode p1 = astName.getParent();
|
IASTNode p1 = astName.getParent();
|
||||||
if( p1 instanceof ICPPASTQualifiedName ){
|
if( p1 instanceof ICPPASTQualifiedName ){
|
||||||
|
@ -183,6 +185,13 @@ public class CPPSemantics {
|
||||||
}
|
}
|
||||||
return p1 instanceof ICPPASTFieldReference;
|
return p1 instanceof ICPPASTFieldReference;
|
||||||
}
|
}
|
||||||
|
public boolean functionCall(){
|
||||||
|
if( astName == null ) return false;
|
||||||
|
IASTNode p1 = astName.getParent();
|
||||||
|
if( p1 instanceof ICPPASTQualifiedName )
|
||||||
|
p1 = p1.getParent();
|
||||||
|
return ( p1 instanceof IASTIdExpression && p1.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected class Cost
|
static protected class Cost
|
||||||
|
@ -316,21 +325,9 @@ public class CPPSemantics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static protected IBinding resolveBinding( IASTName name ){
|
static protected IBinding resolveBinding( IASTName name ){
|
||||||
if( name instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName)name).isFullyQualified() )
|
// if( name instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName)name).isFullyQualified() )
|
||||||
return ((ICPPASTTranslationUnit)name.getTranslationUnit()).resolveBinding();
|
// return ((ICPPASTTranslationUnit)name.getTranslationUnit()).resolveBinding();
|
||||||
|
|
||||||
// if( name.toCharArray().length == 2 && CharArrayUtils.equals( name.toCharArray(), Keywords.cpCOLONCOLON ) ){
|
|
||||||
// IASTNode node = name.getParent();
|
|
||||||
// if( node instanceof ICPPASTQualifiedName ){
|
|
||||||
// ICPPASTQualifiedName qname = (ICPPASTQualifiedName) node;
|
|
||||||
// if( qname.getNames()[0] == name ){
|
|
||||||
// //translation unit
|
|
||||||
// return ((ICPPASTTranslationUnit)node.getTranslationUnit()).resolveBinding();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//1: get some context info off of the name to figure out what kind of lookup we want
|
//1: get some context info off of the name to figure out what kind of lookup we want
|
||||||
LookupData data = createLookupData( name );
|
LookupData data = createLookupData( name );
|
||||||
|
|
||||||
|
@ -363,6 +360,27 @@ public class CPPSemantics {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static IBinding postResolution( IBinding binding, LookupData data ) {
|
private static IBinding postResolution( IBinding binding, LookupData data ) {
|
||||||
|
if( !(data.astName instanceof ICPPASTQualifiedName) && data.functionCall() ){
|
||||||
|
//3.4.2 argument dependent name lookup, aka Koenig lookup
|
||||||
|
try {
|
||||||
|
IScope scope = (binding != null ) ? binding.getScope() : null;
|
||||||
|
if( data.associated.size() > 0 && ( scope == null|| !(scope instanceof ICPPClassScope) ) ){
|
||||||
|
Object [] assoc = new Object[ data.associated.size() ];
|
||||||
|
System.arraycopy( data.associated.keyArray(), 0, assoc, 0, assoc.length );
|
||||||
|
data.ignoreUsingDirectives = true;
|
||||||
|
data.forceQualified = true;
|
||||||
|
for( int i = 0; i < assoc.length; i++ ){
|
||||||
|
if( data.associated.containsKey( assoc[i] ) )
|
||||||
|
lookup( data, assoc[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
binding = resolveAmbiguities( data, data.astName );
|
||||||
|
}
|
||||||
|
} catch ( DOMException e ) {
|
||||||
|
binding = e.getProblem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( binding instanceof ICPPClassType && data.considerConstructors() ){
|
if( binding instanceof ICPPClassType && data.considerConstructors() ){
|
||||||
ICPPClassType cls = (ICPPClassType) binding;
|
ICPPClassType cls = (ICPPClassType) binding;
|
||||||
try {
|
try {
|
||||||
|
@ -434,9 +452,65 @@ public class CPPSemantics {
|
||||||
data.functionParameters = fdtor.getParameters();
|
data.functionParameters = fdtor.getParameters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !(name.getParent() instanceof ICPPASTQualifiedName) && data.functionCall() ){
|
||||||
|
data.associated = getAssociatedScopes( data );
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static private ObjectSet getAssociatedScopes( LookupData data ) {
|
||||||
|
Object [] ps = data.functionParameters;
|
||||||
|
ObjectSet namespaces = new ObjectSet(2);
|
||||||
|
ObjectSet classes = new ObjectSet(2);
|
||||||
|
for( int i = 0; i < ps.length; i++ ){
|
||||||
|
IType p = getSourceParameterType( ps, i );
|
||||||
|
p = getUltimateType( p );
|
||||||
|
try {
|
||||||
|
getAssociatedScopes( p, namespaces, classes );
|
||||||
|
} catch ( DOMException e ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return namespaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private void getAssociatedScopes( IType t, ObjectSet namespaces, ObjectSet classes ) throws DOMException{
|
||||||
|
//3.4.2-2
|
||||||
|
if( t instanceof ICPPClassType ){
|
||||||
|
if( !classes.containsKey( t ) ){
|
||||||
|
classes.put( t );
|
||||||
|
namespaces.put( getContainingNamespaceScope( (IBinding) t ) );
|
||||||
|
|
||||||
|
ICPPClassType cls = (ICPPClassType) t;
|
||||||
|
ICPPBase[] bases = cls.getBases();
|
||||||
|
for( int i = 0; i < bases.length; i++ ){
|
||||||
|
getAssociatedScopes( bases[i].getBaseClass(), namespaces, classes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if( t instanceof IEnumeration ){
|
||||||
|
namespaces.put( getContainingNamespaceScope( (IBinding) t ) );
|
||||||
|
} else if( t instanceof IFunctionType ){
|
||||||
|
IFunctionType ft = (IFunctionType) t;
|
||||||
|
|
||||||
|
getAssociatedScopes( getUltimateType( ft.getReturnType() ), namespaces, classes );
|
||||||
|
IType [] ps = ft.getParameterTypes();
|
||||||
|
for( int i = 0; i < ps.length; i++ ){
|
||||||
|
getAssociatedScopes( getUltimateType( ps[i] ), namespaces, classes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private ICPPNamespaceScope getContainingNamespaceScope( IBinding binding ) throws DOMException{
|
||||||
|
if( binding == null ) return null;
|
||||||
|
IScope scope = binding.getScope();
|
||||||
|
while( scope != null && !(scope instanceof ICPPNamespaceScope) ){
|
||||||
|
scope = scope.getParent();
|
||||||
|
}
|
||||||
|
return (ICPPNamespaceScope) scope;
|
||||||
|
}
|
||||||
|
|
||||||
static private ICPPScope getLookupScope( IASTName name ) throws DOMException{
|
static private ICPPScope getLookupScope( IASTName name ) throws DOMException{
|
||||||
IASTNode parent = name.getParent();
|
IASTNode parent = name.getParent();
|
||||||
|
|
||||||
|
@ -452,10 +526,15 @@ public class CPPSemantics {
|
||||||
return (ICPPScope) CPPVisitor.getContainingScope( name );
|
return (ICPPScope) CPPVisitor.getContainingScope( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
static private void lookup( CPPSemantics.LookupData data, IASTName name ) throws DOMException{
|
static private void lookup( CPPSemantics.LookupData data, Object start ) throws DOMException{
|
||||||
IASTNode node = name;
|
IASTNode node = data.astName;
|
||||||
|
|
||||||
|
ICPPScope scope = null;
|
||||||
|
if( start instanceof ICPPScope )
|
||||||
|
scope = (ICPPScope) start;
|
||||||
|
else
|
||||||
|
scope = getLookupScope( (IASTName) start );
|
||||||
|
|
||||||
ICPPScope scope = getLookupScope( name );
|
|
||||||
while( scope != null ){
|
while( scope != null ){
|
||||||
IASTNode blockItem = CPPVisitor.getContainingBlockItem( node );
|
IASTNode blockItem = CPPVisitor.getContainingBlockItem( node );
|
||||||
if( scope.getPhysicalNode() != blockItem.getParent() && !(scope instanceof ICPPNamespaceScope) )
|
if( scope.getPhysicalNode() != blockItem.getParent() && !(scope instanceof ICPPNamespaceScope) )
|
||||||
|
@ -463,7 +542,7 @@ public class CPPSemantics {
|
||||||
|
|
||||||
List directives = null;
|
List directives = null;
|
||||||
if( !data.usingDirectivesOnly ){
|
if( !data.usingDirectivesOnly ){
|
||||||
IBinding binding = scope.getBinding( name );
|
IBinding binding = scope.getBinding( data.astName );
|
||||||
if( binding == null ){
|
if( binding == null ){
|
||||||
directives = new ArrayList(2);
|
directives = new ArrayList(2);
|
||||||
data.foundItems = lookupInScope( data, scope, blockItem, directives );
|
data.foundItems = lookupInScope( data, scope, blockItem, directives );
|
||||||
|
@ -681,6 +760,11 @@ public class CPPSemantics {
|
||||||
IASTName [] namespaceDefs = null;
|
IASTName [] namespaceDefs = null;
|
||||||
int namespaceIdx = -1;
|
int namespaceIdx = -1;
|
||||||
|
|
||||||
|
if( data.associated.containsKey( scope ) ){
|
||||||
|
//we are looking in scope, remove it from the associated scopes list
|
||||||
|
data.associated.remove( scope );
|
||||||
|
}
|
||||||
|
|
||||||
List found = null;
|
List found = null;
|
||||||
|
|
||||||
if( parent instanceof IASTCompoundStatement ){
|
if( parent instanceof IASTCompoundStatement ){
|
||||||
|
@ -1370,7 +1454,7 @@ public class CPPSemantics {
|
||||||
|
|
||||||
//conversion operators
|
//conversion operators
|
||||||
if( s instanceof ICPPClassType ){
|
if( s instanceof ICPPClassType ){
|
||||||
char[] name = null;//TODO target.toCharArray();
|
char[] name = EMPTY_NAME_ARRAY;//TODO target.toCharArray();
|
||||||
|
|
||||||
if( !CharArrayUtils.equals( name, EMPTY_NAME_ARRAY) ){
|
if( !CharArrayUtils.equals( name, EMPTY_NAME_ARRAY) ){
|
||||||
LookupData data = new LookupData( CharArrayUtils.concat( OPERATOR_, name ));
|
LookupData data = new LookupData( CharArrayUtils.concat( OPERATOR_, name ));
|
||||||
|
@ -1482,7 +1566,7 @@ public class CPPSemantics {
|
||||||
t = ((ITypedef)t).getType();
|
t = ((ITypedef)t).getType();
|
||||||
else {
|
else {
|
||||||
if( t instanceof IPointerType )
|
if( t instanceof IPointerType )
|
||||||
op1 = (IPointerType) t;
|
op2 = (IPointerType) t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1506,6 +1590,8 @@ public class CPPSemantics {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
constInEveryCV2k &= op2.isConst();
|
constInEveryCV2k &= op2.isConst();
|
||||||
|
s = op1.getType();
|
||||||
|
t = op2.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( s instanceof IQualifierType ^ t instanceof IQualifierType ){
|
if( s instanceof IQualifierType ^ t instanceof IQualifierType ){
|
||||||
|
|
|
@ -128,7 +128,6 @@ import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTSimpleDeclSpecifier;
|
import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTSimpleDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author aniefer
|
* @author aniefer
|
||||||
|
@ -1654,7 +1653,7 @@ public class CPPVisitor {
|
||||||
return e.getProblem();
|
return e.getProblem();
|
||||||
}
|
}
|
||||||
} else if( op == IASTUnaryExpression.op_amper ){
|
} else if( op == IASTUnaryExpression.op_amper ){
|
||||||
return new CPointerType( type );
|
return new CPPPointerType( type );
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue