diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 26671500836..bd3df1c5cc1 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IFunction; +import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; @@ -393,4 +394,68 @@ public class AST2CPPTests extends AST2BaseTest { assertInstances( collector, b, 1 ); assertInstances( collector, B2, 1 ); } + + public void testFunctionResolution() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append( "void f( int i ); \n"); //$NON-NLS-1$ + buffer.append( "void f( char c ); \n"); //$NON-NLS-1$ + buffer.append( "void main() { \n"); //$NON-NLS-1$ + buffer.append( " f( 1 ); //calls f( int ); \n"); //$NON-NLS-1$ + buffer.append( " f( 'b' ); \n"); //$NON-NLS-1$ + buffer.append( "} \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector collector = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit( tu, collector ); + IFunction f1 = (IFunction) collector.getName( 0 ).resolveBinding(); + IFunction f2 = (IFunction) collector.getName( 2 ).resolveBinding(); + + assertInstances( collector, f1, 2 ); + assertInstances( collector, f2, 2 ); + } + + public void testSimpleStruct() throws Exception { + StringBuffer buff = new StringBuffer(); + buff.append("typedef struct { \n"); //$NON-NLS-1$ + buff.append(" int x; \n"); //$NON-NLS-1$ + buff.append("} S; \n"); //$NON-NLS-1$ + buff.append("void f() { \n"); //$NON-NLS-1$ + buff.append(" S myS; \n"); //$NON-NLS-1$ + buff.append(" myS.x = 5; \n"); //$NON-NLS-1$ + buff.append("} \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buff.toString(), ParserLanguage.CPP ); + CPPNameCollector collector = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit( tu, collector ); + ICPPClassType anonStruct = (ICPPClassType) collector.getName( 0 ).resolveBinding(); + ICPPField x = (ICPPField) collector.getName(1).resolveBinding(); + ITypedef S = (ITypedef) collector.getName(2).resolveBinding(); + IFunction f = (IFunction) collector.getName(3).resolveBinding(); + IVariable myS = (IVariable) collector.getName(5).resolveBinding(); + + assertInstances( collector, anonStruct, 1 ); + assertInstances( collector, x, 2 ); + assertInstances( collector, S, 2 ); + assertInstances( collector, f, 1 ); + assertInstances( collector, myS, 2 ); + } + public void _testStructureTags() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append( "struct A; \n" ); //$NON-NLS-1$ + buffer.append( "void f(){ \n" ); //$NON-NLS-1$ + buffer.append( " struct A; \n" ); //$NON-NLS-1$ + buffer.append( " struct A * a; \n" ); //$NON-NLS-1$ + buffer.append( "} \n" ); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector collector = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit( tu, collector ); + + ICPPClassType A = (ICPPClassType) collector.getName( 0 ).resolveBinding(); + IVariable a = (IVariable) collector.getName( 4 ).resolveBinding(); + + assertInstances( collector, A, 3 ); + assertInstances( collector, a, 1 ); + } } + diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBase.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBase.java index be72e158874..b037427d7fe 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBase.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPBase.java @@ -16,7 +16,8 @@ package org.eclipse.cdt.core.dom.ast.cpp; * @author Doug Schaefer */ public interface ICPPBase { - + public static final ICPPBase [] EMPTY_BASE_ARRAY = new ICPPBase[0]; + /** * The base class. * diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java index 0bfe2ab88ca..f1081cc68a4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java @@ -27,7 +27,7 @@ public interface ICPPClassType extends ICompositeType { * * @return List of ICPPBase */ - public List getBases(); + public ICPPBase [] getBases(); /** * Get fields is restated here just to point out that this method returns diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java new file mode 100644 index 00000000000..25ff631dae5 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * 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 Dec 10, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; + +/** + * @author aniefer + */ +public class CPPBasicType implements ICPPBasicType { + public static final int IS_LONG = 1; + public static final int IS_SHORT = 1 << 1; + public static final int IS_SIGNED = 1 << 2; + public static final int IS_UNSIGNED = 1 << 3; + protected static final int LAST = IS_UNSIGNED; + + protected int qualifierBits = 0; + protected int type; + + public CPPBasicType( int t, int bits ){ + type = t; + qualifierBits = bits; + } + + public boolean equals( Object object ) { + if( !(object instanceof CPPBasicType) ) + return false; + + CPPBasicType t = (CPPBasicType) object; + return ( type == t.type && qualifierBits == t.qualifierBits ); + } + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBasicType#getType() + */ + public int getType() { + return type; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBasicType#isSigned() + */ + public boolean isSigned() { + return ( qualifierBits & IS_SIGNED ) != 0; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBasicType#isUnsigned() + */ + public boolean isUnsigned() { + return ( qualifierBits & IS_UNSIGNED ) != 0; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBasicType#isShort() + */ + public boolean isShort() { + return ( qualifierBits & IS_SHORT) != 0; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBasicType#isLong() + */ + public boolean isLong() { + return ( qualifierBits & IS_LONG ) != 0; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java index 67409940311..f5e76982db1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java @@ -21,6 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; /** @@ -119,9 +120,9 @@ public class CPPClassType implements ICPPClassType { /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType#getBases() */ - public List getBases() { + public ICPPBase [] getBases() { // TODO Auto-generated method stub - return null; + return ICPPBase.EMPTY_BASE_ARRAY; } /* (non-Javadoc) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java new file mode 100644 index 00000000000..2de89a649f0 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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 Dec 10, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IParameter; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; + +/** + * @author aniefer + */ +public class CPPParameter implements IParameter { + private IType type = null; + private IASTDeclarator declarator = null; + public CPPParameter( IASTDeclarator declarator ){ + this.declarator = declarator; + } + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getName() + */ + public String getName() { + return declarator.getName().toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray() + */ + public char[] getNameCharArray() { + return declarator.getName().toCharArray(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getScope() + */ + public IScope getScope() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getPhysicalNode() + */ + public IASTNode getPhysicalNode() { + return declarator; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IVariable#getType() + */ + public IType getType() { + if( type == null ) + type = CPPVisitor.createType( declarator ); + return type; + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPointerType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPointerType.java new file mode 100644 index 00000000000..cee3d20326d --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPointerType.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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 Dec 10, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.IASTPointer; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; + +/** + * @author aniefer + */ +public class CPPPointerType implements IPointerType { + private IASTPointer operator = null; + private IType type = null; + /** + * @param type + * @param operator + */ + public CPPPointerType(IType type, IASTPointer operator) { + this.type = type; + this.operator = operator; + } + + /** + * @param type2 + */ + public CPPPointerType(IType type) { + this.type = type; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IPointerType#getType() + */ + public IType getType() { + return type; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IPointerType#isConst() + */ + public boolean isConst() { + return ( operator != null ) ? operator.isConst() : false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IPointerType#isVolatile() + */ + public boolean isVolatile() { + return ( operator != null ) ? operator.isVolatile() : false; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java new file mode 100644 index 00000000000..139d6672381 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java @@ -0,0 +1,1317 @@ +/********************************************************************** + * 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 - Initial API and implementation + **********************************************************************/ +/* + * Created on Dec 8, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; +import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTExpressionList; +import org.eclipse.cdt.core.dom.ast.IASTForStatement; +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IEnumeration; +import org.eclipse.cdt.core.dom.ast.IFunction; +import org.eclipse.cdt.core.dom.ast.IParameter; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IQualifierType; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +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.ICPPBasicType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ObjectMap; +import org.eclipse.cdt.core.parser.util.ObjectSet; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; +import org.eclipse.cdt.internal.core.parser.pst.ISymbol; +import org.eclipse.cdt.internal.core.parser.pst.ITypeInfo; + +/** + * @author aniefer + */ +public class CPPSemantics { + + public static final char[] EMPTY_NAME_ARRAY = new char[0]; + + static protected class LookupData + { + public char[] name; + 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 inheritanceChain; //used to detect circular inheritance + + public boolean qualified = false; + public boolean ignoreUsingDirectives = false; + public boolean usingDirectivesOnly = false; + public boolean forDefinition = false; + public boolean typesOnly = false; + public List foundItems = null; + public Object [] functionParameters; + public boolean forUserDefinedConversion; + + public LookupData( char[] n ){ + name = n; + } + } + + static protected class Cost + { + public Cost( IType s, IType t ){ + source = s; + target = t; + } + + public IType source; + public IType target; + + public boolean targetHadReference = false; + + public int lvalue; + public int promotion; + public int conversion; + public int qualification; + public int userDefined; + public int rank = -1; + public int detail; + + //Some constants to help clarify things + public static final int AMBIGUOUS_USERDEFINED_CONVERSION = 1; + + public static final int NO_MATCH_RANK = -1; + public static final int IDENTITY_RANK = 0; + public static final int LVALUE_OR_QUALIFICATION_RANK = 0; + public static final int PROMOTION_RANK = 1; + public static final int CONVERSION_RANK = 2; + public static final int DERIVED_TO_BASE_CONVERSION = 3; + public static final int USERDEFINED_CONVERSION_RANK = 4; + public static final int ELLIPSIS_CONVERSION = 5; + + public int compare( Cost cost ){ + int result = 0; + + if( rank != cost.rank ){ + return cost.rank - rank; + } + + if( userDefined != 0 || cost.userDefined != 0 ){ + if( userDefined == 0 || cost.userDefined == 0 ){ + return cost.userDefined - userDefined; + } + if( (userDefined == AMBIGUOUS_USERDEFINED_CONVERSION || cost.userDefined == AMBIGUOUS_USERDEFINED_CONVERSION) || + (userDefined != cost.userDefined ) ) + return 0; + + // else they are the same constructor/conversion operator and are ranked + //on the standard conversion sequence + + } + + if( promotion > 0 || cost.promotion > 0 ){ + result = cost.promotion - promotion; + } + if( conversion > 0 || cost.conversion > 0 ){ + if( detail == cost.detail ){ + result = cost.conversion - conversion; + } else { + result = cost.detail - detail; + } + } + + if( result == 0 ){ + if( cost.qualification != qualification ){ + return cost.qualification - qualification; + } else if( (cost.qualification == qualification) && qualification == 0 ){ + return 0; + } else { + IPointerType op1, op2; + IType t1 = cost.target, t2 = target; + int subOrSuper = 0; + while( true ){ + op1 = null; + op2 = null; + while( true ){ + if( t1 instanceof ITypedef ) + t1 = ((ITypedef)t1).getType(); + else { + if( t1 instanceof IPointerType ) + op1 = (IPointerType) t1; + break; + } + } + while( true ){ + if( t2 instanceof ITypedef ) + t2 = ((ITypedef)t2).getType(); + else { + if( t2 instanceof IPointerType ) + op1 = (IPointerType) t2; + break; + } + } + if( op1 == null || op2 == null ) + break; + + int cmp = ( op1.isConst() ? 1 : 0 ) + ( op1.isVolatile() ? 1 : 0 ) - + ( op2.isConst() ? 1 : 0 ) + ( op2.isVolatile() ? 1 : 0 ); + + if( subOrSuper == 0 ) + subOrSuper = cmp; + else if( subOrSuper > 0 ^ cmp > 0) { + result = -1; + break; + } + + } + if( result == -1 ){ + result = 0; + } else { + if( op1 == op2 ){ + result = subOrSuper; + } else { + result = op1 != null ? 1 : -1; + } + } + } + } + + return result; + } + } + static protected IBinding resolveBinding( IASTName name ){ + //1: get some context info off of the name to figure out what kind of lookup we want + LookupData data = createLookupData( name ); + + //2: lookup + lookup( data, name ); + + //3: resolve ambiguities + IASTName found = resolveAmbiguities( data, name ); + if( found != null ) { + IBinding binding = found.resolveBinding(); + if( binding != null && data.forDefinition ){ + addDefinition( binding, name ); + } + return binding; + } + return null; + } + + static private CPPSemantics.LookupData createLookupData( IASTName name ){ + CPPSemantics.LookupData data = new CPPSemantics.LookupData( name.toCharArray() ); + IASTNode parent = name.getParent(); + if( parent instanceof ICPPASTQualifiedName ){ + data.qualified = ((ICPPASTQualifiedName)parent).getNames()[0] != name; + parent = parent.getParent(); + if( parent instanceof IASTDeclarator ){ + data.forDefinition = true; + } else if( parent instanceof IASTIdExpression ){ + parent = parent.getParent(); + if( parent instanceof IASTFunctionCallExpression ){ + IASTExpression exp = ((IASTFunctionCallExpression)parent).getParameterExpression(); + if( exp instanceof IASTExpressionList ) + data.functionParameters = ((IASTExpressionList) exp ).getExpressions(); + else if( exp != null ) + data.functionParameters = new IASTExpression [] { exp }; + } + } + } else if( parent instanceof IASTDeclarator ){ + data.forDefinition = true; + } else if ( parent instanceof ICPPASTBaseSpecifier || + parent instanceof ICPPASTElaboratedTypeSpecifier) + { + data.typesOnly = true; + } else if( parent instanceof IASTIdExpression ){ + parent = parent.getParent(); + if( parent instanceof IASTFunctionCallExpression ){ + IASTExpression exp = ((IASTFunctionCallExpression)parent).getParameterExpression(); + if( exp instanceof IASTExpressionList ) + data.functionParameters = ((IASTExpressionList) exp ).getExpressions(); + else if( exp != null ) + data.functionParameters = new IASTExpression [] { exp }; + } + } else if( parent instanceof ICPPASTFieldReference ){ + data.qualified = true; + } + return data; + } + + static private void lookup( CPPSemantics.LookupData data, IASTName name ){ + IASTNode node = name; + + ICPPScope scope = (ICPPScope) CPPVisitor.getContainingScope( node ); + while( scope != null ){ + IASTNode blockItem = CPPVisitor.getContainingBlockItem( node ); + if( scope.getPhysicalNode() != blockItem.getParent() ) + blockItem = node; + + List directives = null; + if( !data.usingDirectivesOnly ){ + directives = new ArrayList(2); + data.foundItems = lookupInScope( data, scope, blockItem, directives ); + } + + + if( !data.ignoreUsingDirectives ) { + data.visited.clear(); + if( data.foundItems == null || data.foundItems.isEmpty() ){ + List transitives = lookupInNominated( data, scope, null ); + + processDirectives( data, scope, transitives ); + if( directives != null && directives.size() != 0 ) + processDirectives( data, scope, directives ); + + while( !data.usingDirectives.isEmpty() && data.usingDirectives.get( scope ) != null ){ + if( transitives != null ) + transitives.clear(); + transitives = lookupInNominated( data, scope, transitives ); + + if( !data.qualified || data.foundItems == null ){ + processDirectives( data, scope, transitives ); + } + } + } + } + + if( data.foundItems != null && !data.foundItems.isEmpty() ) + return; + + if( !data.usingDirectivesOnly && scope instanceof ICPPClassScope ){ + data.foundItems = lookupInParents( data, (ICPPClassScope) scope ); + } + + if( data.foundItems != null && !data.foundItems.isEmpty() ) + return; + + //if still not found, loop and check our containing scope + if( data.qualified && !data.usingDirectives.isEmpty() ) + data.usingDirectivesOnly = true; + + if( blockItem != null ) + node = blockItem; + scope = (ICPPScope) scope.getParent(); + } + } + + private static List lookupInParents( CPPSemantics.LookupData data, ICPPClassScope lookIn ){ + ICPPASTCompositeTypeSpecifier compositeTypeSpec = (ICPPASTCompositeTypeSpecifier) lookIn.getPhysicalNode(); + ICPPASTBaseSpecifier [] bases = compositeTypeSpec.getBaseSpecifiers(); + + List inherited = null; + List result = null; + + if( bases.length == 0 ) + return null; + + //use data to detect circular inheritance + if( data.inheritanceChain == null ) + data.inheritanceChain = new ObjectSet( 2 ); + + data.inheritanceChain.put( lookIn ); + + int size = bases.length; + for( int i = 0; i < size; i++ ) + { + ICPPClassType binding = (ICPPClassType) bases[i].getName().resolveBinding(); + ICPPClassScope parent = (ICPPClassScope) binding.getCompositeScope(); + + if( parent == null ) + continue; + + if( !bases[i].isVirtual() || !data.visited.containsKey( parent ) ){ + if( bases[i].isVirtual() ){ + if( data.visited == ObjectSet.EMPTY_SET ) + data.visited = new ObjectSet(2); + data.visited.put( parent ); + } + + //if the inheritanceChain already contains the parent, then that + //is circular inheritance + if( ! data.inheritanceChain.containsKey( parent ) ){ + //is this name define in this scope? + inherited = lookupInScope( data, parent, null, null ); + + if( inherited == null || inherited.isEmpty() ){ + inherited = lookupInParents( data, parent ); + } + } else { + //throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance ); + } + } + + if( inherited != null && !inherited.isEmpty() ){ + if( result == null || result.isEmpty() ){ + result = inherited; + } else if ( inherited != null && !inherited.isEmpty() ) { + for( int j = 0; j < result.size(); j++ ) { + IASTName n = (IASTName) result.get(j); + if( !checkAmbiguity( n, inherited ) ){ + //throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + return null; + } + } + } + } else { + inherited = null; //reset temp for next iteration + } + } + + data.inheritanceChain.remove( lookIn ); + + return result; + } + + private static boolean checkAmbiguity( Object obj1, Object obj2 ){ + //it is not ambiguous if they are the same thing and it is static or an enumerator + if( obj1 == obj2 ){ + List objList = ( obj1 instanceof List ) ? (List) obj1 : null; + int objListSize = ( objList != null ) ? objList.size() : 0; + ISymbol symbol = ( objList != null ) ? (ISymbol) objList.get(0) : ( ISymbol )obj1; + int idx = 1; + while( symbol != null ) { + ITypeInfo type = ((ISymbol)obj1).getTypeInfo(); + if( !type.checkBit( ITypeInfo.isStatic ) && !type.isType( ITypeInfo.t_enumerator ) ){ + return false; + } + + if( objList != null && idx < objListSize ){ + symbol = (ISymbol) objList.get( idx++ ); + } else { + symbol = null; + } + } + return true; + } + return false; + } + + static private void processDirectives( CPPSemantics.LookupData data, IScope scope, List directives ){ + if( directives == null || directives.size() == 0 ) + return; + + ICPPScope enclosing = null; + IScope temp = null; + + int size = directives.size(); + for( int i = 0; i < size; i++ ){ + IASTName qualName = ((ICPPASTUsingDirective)directives.get(i)).getQualifiedName(); + IBinding binding = qualName.resolveBinding(); + if( binding instanceof ICPPNamespace ){ + temp = ((ICPPNamespace)binding).getNamespaceScope(); + } else + continue; + + //namespace are searched at most once + if( !data.visited.containsKey( temp ) ){ + enclosing = getClosestEnclosingScope( scope, temp ); + + //data.usingDirectives is a map from enclosing scope to a list + //of namespaces to consider when we reach that enclosing scope + List list = data.usingDirectives.isEmpty() ? null : (List) data.usingDirectives.get( enclosing ); + if( list == null ){ + list = new ArrayList(); + + if( data.usingDirectives == ObjectMap.EMPTY_MAP ){ + data.usingDirectives = new ObjectMap(2); + } + data.usingDirectives.put( enclosing, list ); + } + list.add( temp ); + } + } + + } + + static private ICPPScope getClosestEnclosingScope( IScope scope1, IScope scope2 ){ + ObjectSet set = new ObjectSet( 2 ); + IScope parent = scope1; + while( parent != null ){ + set.put( parent ); + parent = parent.getParent(); + } + parent = scope2; + while( parent != null && !set.containsKey( parent ) ){ + parent = parent.getParent(); + } + return (ICPPScope) parent; + } + + /** + * + * @param scope + * @return List of encountered using directives + */ + static private List lookupInScope( CPPSemantics.LookupData data, ICPPScope scope, IASTNode blockItem, List usingDirectives ) { + IASTName possible = null; + IASTNode [] nodes = null; + IASTNode parent = scope.getPhysicalNode(); + + List found = null; + + if( parent instanceof IASTCompoundStatement ){ + IASTCompoundStatement compound = (IASTCompoundStatement) parent; + nodes = compound.getStatements(); + } else if ( parent instanceof IASTTranslationUnit ){ + IASTTranslationUnit translation = (IASTTranslationUnit) parent; + nodes = translation.getDeclarations(); + } else if ( parent instanceof ICPPASTCompositeTypeSpecifier ){ + ICPPASTCompositeTypeSpecifier comp = (ICPPASTCompositeTypeSpecifier) parent; + nodes = comp.getMembers(); + } else if ( parent instanceof ICPPASTNamespaceDefinition ){ + nodes = ((ICPPASTNamespaceDefinition)parent).getDeclarations(); + } + + int idx = -1; + IASTNode item = ( nodes != null ? (nodes.length > 0 ? nodes[++idx] : null ) : parent ); + + while( item != null ) { + if( item == null || item == blockItem || ( blockItem != null && ((ASTNode)item).getOffset() > ((ASTNode) blockItem).getOffset() )) + break; + + if( item instanceof ICPPASTUsingDirective && !data.ignoreUsingDirectives ) { + if( usingDirectives != null ) + usingDirectives.add( item ); + } else { + possible = collectResult( data, item, (item == parent) ); + if( possible != null ){ + if( found == null ) + found = new ArrayList(2); + found.add( possible ); + } + } + if( idx > -1 && ++idx < nodes.length ){ + item = nodes[idx]; + } else { + item = null; + } + } + return found; + } + + static private List lookupInNominated( CPPSemantics.LookupData data, ICPPScope scope, List transitives ){ + if( data.usingDirectives.isEmpty() ) + return transitives; + + List directives = null; + ICPPScope temp = null; + + directives = (List) data.usingDirectives.remove( scope ); + if( directives == null || directives.size() == 0 ) { + return transitives; + } + for( int i = 0; i < directives.size(); i++ ){ + temp = (ICPPScope) directives.get(i); + if( !data.visited.containsKey( temp ) ){ + if( data.visited == ObjectSet.EMPTY_SET ) { + data.visited = new ObjectSet(2); + } + data.visited.put( temp ); + List usings = new ArrayList(2); + List found = lookupInScope( data, temp, null, usings ); + if( data.foundItems == null ) + data.foundItems = found; + else if( found != null ) + data.foundItems.addAll( found ); + + + //only consider the transitive using directives if we are an unqualified + //lookup, or we didn't find the name in decl + if( usings != null && usings.size() > 0 && (!data.qualified || found == null ) ){ + if( transitives == null ) + transitives = new ArrayList(2); + transitives.addAll( usings ); + } + } + } + return transitives; + } + + static private IASTName collectResult( CPPSemantics.LookupData data, IASTNode node, boolean checkAux ){ + IASTDeclaration declaration = null; + if( node instanceof IASTDeclaration ) + declaration = (IASTDeclaration) node; + if( node instanceof IASTDeclarationStatement ) + declaration = ((IASTDeclarationStatement)node).getDeclaration(); + else if( node instanceof IASTForStatement ) + declaration = ((IASTForStatement)node).getInitDeclaration(); + + if( declaration == null ) + return null; + + if( declaration instanceof IASTSimpleDeclaration ){ + IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration; + if( !data.typesOnly ) { + IASTDeclarator [] declarators = simpleDeclaration.getDeclarators(); + for( int i = 0; i < declarators.length; i++ ){ + IASTDeclarator declarator = declarators[i]; + IASTName declaratorName = declarator.getName(); + if( CharArrayUtils.equals( declaratorName.toCharArray(), data.name ) ){ + return declaratorName; + } + } + } + + //decl spec + IASTDeclSpecifier declSpec = simpleDeclaration.getDeclSpecifier(); + if( declSpec instanceof IASTElaboratedTypeSpecifier ){ + IASTName elabName = ((IASTElaboratedTypeSpecifier)declSpec).getName(); + if( CharArrayUtils.equals( elabName.toCharArray(), data.name ) ){ + return elabName; + } + } else if( declSpec instanceof ICPPASTCompositeTypeSpecifier ){ + IASTName compName = ((IASTCompositeTypeSpecifier)declSpec).getName(); + if( CharArrayUtils.equals( compName.toCharArray(), data.name ) ){ + return compName; + } + } else if( declSpec instanceof IASTEnumerationSpecifier ){ + IASTEnumerationSpecifier enumeration = (IASTEnumerationSpecifier) declSpec; + IASTName eName = enumeration.getName(); + if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ + return eName; + } + if( !data.typesOnly ) { + //check enumerators too + IASTEnumerator [] list = enumeration.getEnumerators(); + for( int i = 0; i < list.length; i++ ) { + IASTEnumerator enumerator = list[i]; + if( enumerator == null ) break; + eName = enumerator.getName(); + if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ + return eName; + } + } + } + } + } + if( data.typesOnly ) + return null; + + if( declaration instanceof IASTFunctionDefinition ){ + IASTFunctionDefinition functionDef = (IASTFunctionDefinition) declaration; + IASTFunctionDeclarator declarator = functionDef.getDeclarator(); + + //check the function itself + IASTName declName = declarator.getName(); + if( declName instanceof ICPPASTQualifiedName ){ + IASTName [] names = ((ICPPASTQualifiedName)declName).getNames(); + declName = names[ names.length - 1 ]; + } + if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ + return declName; + } + if( checkAux ) { + //check the parameters + IASTParameterDeclaration [] parameters = declarator.getParameters(); + for( int i = 0; i < parameters.length; i++ ){ + IASTParameterDeclaration parameterDeclaration = parameters[i]; + if( parameterDeclaration == null ) break; + declName = parameterDeclaration.getDeclarator().getName(); + if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ + return declName; + } + } + } + } else if( declaration instanceof ICPPASTNamespaceDefinition ){ + IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName(); + if( CharArrayUtils.equals( namespaceName.toCharArray(), data.name ) ) + return namespaceName; + } + + return null; + } + + private static void addDefinition( IBinding binding, IASTName name ){ + if( binding instanceof IFunction ){ + IASTNode node = name.getParent(); + if( node instanceof ICPPASTQualifiedName ) + node = node.getParent(); + if( node instanceof IASTFunctionDeclarator ){ + ((CPPFunction)binding).addDefinition( (IASTFunctionDeclarator) node ); + } + } + } + + static private IASTName resolveAmbiguities( CPPSemantics.LookupData data, IASTName name ) { + if( data.foundItems == null || data.foundItems.size() == 0 ) + return null; + + if( data.foundItems.size() == 1 ){ + return (IASTName) data.foundItems.get(0); + } + + IASTName type = null; + IASTName obj = null; + List fns = null; + for( int i = 0; i < data.foundItems.size(); i++ ){ + IASTName n = (IASTName) data.foundItems.get( i ); + IASTNode parent = n.getParent(); + if( parent instanceof IASTFunctionDeclarator ){ + if( fns == null ) + fns = new ArrayList(2); + fns.add( n ); + } else if( parent instanceof IASTDeclarator ){ + if( obj == null ){ + obj = n; + } else { + //TODO + } + } else if( parent instanceof ICPPASTElaboratedTypeSpecifier || + parent instanceof IASTEnumerationSpecifier || + parent instanceof ICPPASTCompositeTypeSpecifier ) + { + if( type == null ){ + type = n; + } else { + //TODO + } + } + } + + if( type != null ) { + if( obj == null && fns == null ) + return type; + IScope typeScope = type.resolveBinding().getScope(); + if( obj != null && obj.resolveBinding().getScope() != typeScope ){ + return null;//ambiguous + } else if( fns != null ){ + for( int i = 0; i < fns.size(); i++ ){ + if( ((IASTName)fns.get(i)).resolveBinding().getScope() != typeScope ) + return null; //ambiguous + } + } + } + if( fns != null){ + if( obj != null ) + return null; //ambiguous + return resolveFunction( data, fns ); + } + + return obj; + } + + static private boolean functionHasParameters( ICPPASTFunctionDeclarator function, ICPPASTParameterDeclaration [] params ){ + return false; + } + static private void reduceToViable( LookupData data, List functions ){ + Object [] fParams = data.functionParameters; + int numParameters = ( fParams != null ) ? fParams.length : 0; + int num; + + //Trim the list down to the set of viable functions + IASTName fName; + ICPPASTFunctionDeclarator function = null; + int size = functions.size(); + for( int i = 0; i < size; i++ ){ + fName = (IASTName) functions.get(i); + //sanity check + if( !( fName.getParent() instanceof IASTFunctionDeclarator ) ){ + functions.remove( i-- ); + size--; + continue; + } + function = (ICPPASTFunctionDeclarator) fName.getParent(); + num = function.getParameters().length; + + //if there are m arguments in the list, all candidate functions having m parameters + //are viable + if( num == numParameters ){ + if( data.forDefinition && !functionHasParameters( function, (ICPPASTParameterDeclaration[]) data.functionParameters ) ){ + functions.remove( i-- ); + size--; + } + continue; + } + //check for void + else if( numParameters == 0 && num == 1 ){ + IASTParameterDeclaration param = function.getParameters()[0]; + IASTDeclSpecifier declSpec = param.getDeclSpecifier(); + if( declSpec instanceof IASTSimpleDeclSpecifier ){ + if( ((IASTSimpleDeclSpecifier)declSpec).getType() == IASTSimpleDeclSpecifier.t_void && + param.getDeclarator().getPointerOperators().length == 0 ) + { + continue; + } + } + } + + //A candidate function having fewer than m parameters is viable only if it has an + //ellipsis in its parameter list. + if( num < numParameters ){ + if( function.takesVarArgs() ) { + continue; + } + //not enough parameters, remove it + functions.remove( i-- ); + size--; + } + //a candidate function having more than m parameters is viable only if the (m+1)-st + //parameter has a default argument + else { + IASTParameterDeclaration [] params = function.getParameters(); + for( int j = num - 1; j > ( numParameters - num); j-- ){ + if( params[j].getDeclarator().getInitializer() == null ){ + functions.remove( i-- ); + size--; + break; + } + } + } + } + } + + static private IType getSourceParameterType( Object [] params, int idx ){ + if( params instanceof IASTExpression [] ){ + IASTExpression [] exps = (IASTExpression[]) params; + return CPPVisitor.getExpressionType( exps[ idx ] ); + } + return null; + } + static private IASTName resolveFunction( CPPSemantics.LookupData data, List fns ){ + //reduce our set of candidate functions to only those who have the right number of parameters + reduceToViable( data, fns ); + + IASTName bestFn = null; //the best function + IASTName currFn = null; //the function currently under consideration + Cost [] bestFnCost = null; //the cost of the best function + Cost [] currFnCost = null; //the cost for the current function + + IType source = null; //parameter we are called with + IType target = null; //function's parameter +// ITypeInfo voidInfo = null; //used to compare f() and f(void) + + int comparison; + Cost cost = null; //the cost of converting source to target + Cost temp = null; //the cost of using a user defined conversion to convert source to target + + boolean hasWorse = false; //currFn has a worse parameter fit than bestFn + boolean hasBetter = false; //currFn has a better parameter fit than bestFn + boolean ambiguous = false; //ambiguity, 2 functions are equally good + boolean currHasAmbiguousParam = false; //currFn has an ambiguous parameter conversion (ok if not bestFn) + boolean bestHasAmbiguousParam = false; //bestFn has an ambiguous parameter conversion (not ok, ambiguous) + + Object [] sourceParameters = null; //the parameters the function is being called with + IASTParameterDeclaration [] targetParameters = null; //the current function's parameters + + int numFns = fns.size(); + int numSourceParams = ( data.functionParameters != null ) ? data.functionParameters.length : 0; + + sourceParameters = data.functionParameters; + + for( int fnIdx = 0; fnIdx < numFns; fnIdx++ ){ + currFn = (IASTName) fns.get( fnIdx ); + + if( bestFn != null ){ + if( bestFn.resolveBinding() == currFn.resolveBinding() ) + continue; + } + + ICPPASTFunctionDeclarator currDtor = (ICPPASTFunctionDeclarator) currFn.getParent(); + targetParameters = currDtor.getParameters(); + + int numTargetParams = targetParameters.length; + if( currFnCost == null ){ + currFnCost = new Cost [ numSourceParams ]; + } + + comparison = 0; + boolean varArgs = false; + + for( int j = 0; j < numSourceParams; j++ ){ + source = getSourceParameterType( sourceParameters, j ); + + if( j < numTargetParams ){ + IParameter param = (IParameter) targetParameters[j].getDeclarator().getName().resolveBinding(); + target = param.getType(); + } else + varArgs = true; + + if( varArgs ){ + cost = new Cost( source, null ); + cost.rank = Cost.ELLIPSIS_CONVERSION; + } /*else if ( target.getHasDefault() && source.isType( ITypeInfo.t_void ) && !source.hasPtrOperators() ){ + //source is just void, ie no parameter, if target had a default, then use that + cost = new Cost( source, target ); + cost.rank = Cost.IDENTITY_RANK; + }*/ else if( source.equals( target ) ){ + cost = new Cost( source, target ); + cost.rank = Cost.IDENTITY_RANK; //exact match, no cost + } else { + cost = checkStandardConversionSequence( source, target ); + + //12.3-4 At most one user-defined conversion is implicitly applied to + //a single value. (also prevents infinite loop) + if( cost.rank == Cost.NO_MATCH_RANK && !data.forUserDefinedConversion ){ + temp = checkUserDefinedConversionSequence( source, target ); + if( temp != null ){ + cost = temp; + } + } + } + + currFnCost[ j ] = cost; + } + + + hasWorse = false; + hasBetter = false; + //In order for this function to be better than the previous best, it must + //have at least one parameter match that is better that the corresponding + //match for the other function, and none that are worse. + for( int j = 0; j < numSourceParams; j++ ){ + if( currFnCost[ j ].rank < 0 ){ + hasWorse = true; + hasBetter = false; + break; + } + + //an ambiguity in the user defined conversion sequence is only a problem + //if this function turns out to be the best. + currHasAmbiguousParam = ( currFnCost[ j ].userDefined == 1 ); + + if( bestFnCost != null ){ + comparison = currFnCost[ j ].compare( bestFnCost[ j ] ); + hasWorse |= ( comparison < 0 ); + hasBetter |= ( comparison > 0 ); + } else { + hasBetter = true; + } + } + + //If function has a parameter match that is better than the current best, + //and another that is worse (or everything was just as good, neither better nor worse). + //then this is an ambiguity (unless we find something better than both later) + ambiguous |= ( hasWorse && hasBetter ) || ( !hasWorse && !hasBetter ); + + if( !hasWorse ){ + if( hasBetter ){ + //the new best function. + ambiguous = false; + bestFnCost = currFnCost; + bestHasAmbiguousParam = currHasAmbiguousParam; + currFnCost = null; + bestFn = currFn; + } + } + } + + + if( ambiguous || bestHasAmbiguousParam ){ + return null; //TODO throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } + + return bestFn; + } + + static private Cost checkStandardConversionSequence( IType source, IType target ) { + Cost cost = lvalue_to_rvalue( source, target ); + + if( cost.source == null || cost.target == null ){ + return cost; + } + + if( cost.source.equals( cost.target ) ){ + cost.rank = Cost.IDENTITY_RANK; + return cost; + } + + qualificationConversion( cost ); + + //if we can't convert the qualifications, then we can't do anything + if( cost.qualification == 0 ){ + return cost; + } + + //was the qualification conversion enough? + IType s = getUltimateType( cost.source ); + IType t = getUltimateType( cost.target ); + if( s.equals( t ) ){ + return cost; + } + + promotion( cost ); + if( cost.promotion > 0 || cost.rank > -1 ){ + return cost; + } + + conversion( cost ); + + if( cost.rank > -1 ) + return cost; + + derivedToBaseConversion( cost ); + + return cost; + } + + static private Cost checkUserDefinedConversionSequence( IType source, IType target ) { + Cost cost = null; +// Cost constructorCost = null; +// Cost conversionCost = null; + +// IType s = getUltimateType( source ); +// IType t = getUltimateType( target ); +// //ISymbol sourceDecl = null; +// IASTName constructor = null; +// IASTName conversion = null; +// +// //constructors +// if( t instanceof ICPPClassType ){ +// LookupData data = new LookupData( EMPTY_NAME_ARRAY ); +// data.forUserDefinedConversion = true; +// data.functionParameters = new Object [] { source }; +// +// if( !container.getConstructors().isEmpty() ){ +// ArrayList constructors = new ArrayList( container.getConstructors() ); +// constructor = resolveFunction( data, constructors ); +// } +// if( constructor != null && constructor.getTypeInfo().checkBit( ITypeInfo.isExplicit ) ){ +// constructor = null; +// } +// } + + //conversion operators +// if( source.getType() == ITypeInfo.t_type ){ +// source = getFlatTypeInfo( source, provider ); +// sourceDecl = ( source != null ) ? source.getTypeSymbol() : null; +// +// if( sourceDecl != null && (sourceDecl instanceof IContainerSymbol) ){ +// char[] name = target.toCharArray(); +// +// if( !CharArrayUtils.equals( name, EMPTY_NAME_ARRAY) ){ +// +// LookupData data = new LookupData( CharArrayUtils.concat( OPERATOR_, name )){ //$NON-NLS-1$ +// public List getParameters() { return Collections.EMPTY_LIST; } +// public TypeFilter getFilter() { return FUNCTION_FILTER; } +// }; +// data.forUserDefinedConversion = true; +// data.foundItems = lookupInContained( data, (IContainerSymbol) sourceDecl ); +// conversion = (data.foundItems != null ) ? (IParameterizedSymbol)resolveAmbiguities( data ) : null; +// } +// } +// } +// +// if( constructor != null ){ +// IType info = provider.getTypeInfo( ITypeInfo.t_type ); +// info.setTypeSymbol( constructor.getContainingSymbol() ); +// constructorCost = checkStandardConversionSequence( info, target ); +// } +// if( conversion != null ){ +// IType info = provider.getTypeInfo( target.getType() ); +// info.setTypeSymbol( target.getTypeSymbol() ); +// conversionCost = checkStandardConversionSequence( info, target ); +// } + +// //if both are valid, then the conversion is ambiguous +// if( constructorCost != null && constructorCost.rank != Cost.NO_MATCH_RANK && +// conversionCost != null && conversionCost.rank != Cost.NO_MATCH_RANK ) +// { +// cost = constructorCost; +// cost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION; +// cost.rank = Cost.USERDEFINED_CONVERSION_RANK; +// } else { +// if( constructorCost != null && constructorCost.rank != Cost.NO_MATCH_RANK ){ +// cost = constructorCost; +// cost.userDefined = constructor.hashCode(); +// cost.rank = Cost.USERDEFINED_CONVERSION_RANK; +// } else if( conversionCost != null && conversionCost.rank != Cost.NO_MATCH_RANK ){ +// cost = conversionCost; +// cost.userDefined = conversion.hashCode(); +// cost.rank = Cost.USERDEFINED_CONVERSION_RANK; +// } +// } + return cost; + } + + static protected IType getUltimateType( IType type ){ + while( true ){ + if( type instanceof ITypedef ) + type = ((ITypedef)type).getType(); + else if( type instanceof IQualifierType ) + type = ((IQualifierType)type).getType(); + else if( type instanceof IPointerType ) + type = ((IPointerType) type).getType(); + else if( type instanceof ICPPReferenceType ) + type = ((ICPPReferenceType)type).getType(); + else + return type; + } + } + + static private boolean isCompleteType( IType type ){ + type = getUltimateType( type ); + if( type instanceof ICPPClassType ){ + if( ((ICPPClassType) type).getPhysicalNode() instanceof ICPPASTElaboratedTypeSpecifier ) + return false; + } + return true; + } + static private Cost lvalue_to_rvalue( IType source, IType target ){ + Cost cost = new Cost( source, target ); + + if( ! isCompleteType( source ) ){ + cost.rank = Cost.NO_MATCH_RANK; + return cost; + } + + if( source instanceof ICPPReferenceType ){ + source = ((ICPPReferenceType) source).getType(); + } + if( target instanceof ICPPReferenceType ){ + target = ((ICPPReferenceType) target).getType(); + cost.targetHadReference = true; + } + + cost.source = source; + cost.target = target; + + return cost; + } + + static private void qualificationConversion( Cost cost ){ + boolean canConvert = true; + + IPointerType op1, op2; + IType s = cost.source, t = cost.target; + boolean constInEveryCV2k = true; + while( true ){ + op1 = null; + op2 = null; + while( true ){ + if( s instanceof ITypedef ) + s = ((ITypedef)s).getType(); + else { + if( s instanceof IPointerType ) + op1 = (IPointerType) s; + break; + } + } + while( true ){ + if( t instanceof ITypedef ) + t = ((ITypedef)t).getType(); + else { + if( t instanceof IPointerType ) + op1 = (IPointerType) t; + break; + } + } + if( op1 == null && op2 == null ) + break; + else if( op1 == null ^ op2 == null) { + canConvert = false; + break; + } + + //if const is in cv1,j then const is in cv2,j. Similary for volatile + if( ( op1.isConst() && !op2.isConst() ) || ( op1.isVolatile() && !op2.isVolatile() ) ) { + canConvert = false; + break; + } + //if cv1,j and cv2,j are different then const is in every cv2,k for 0 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK; + } + static private void conversion( Cost cost ){ + IType src = cost.source; + IType trg = cost.target; + + int temp = -1; + + cost.conversion = 0; + cost.detail = 0; + +// if( !src.hasSamePtrs( trg ) ){ +// return; +// } +// + IType s = getUltimateType( src ); + IType t = getUltimateType( trg ); + + + if( s instanceof ICPPClassType ){ + //4.10-2 an rvalue of type "pointer to cv T", where T is an object type can be + //converted to an rvalue of type "pointer to cv void" + if( t instanceof IBasicType && ((IBasicType)t).getType() == IBasicType.t_void ){ + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + cost.detail = 2; + return; + } + //4.10-3 An rvalue of type "pointer to cv D", where D is a class type can be converted + //to an rvalue of type "pointer to cv B", where B is a base class of D. + else if( t instanceof ICPPClassType ){ + temp = hasBaseClass( (ICPPClassType)s, (ICPPClassType) t, true ); + cost.rank = ( temp > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; + cost.conversion = ( temp > -1 ) ? temp : 0; + cost.detail = 1; + return; + } + } else if( t instanceof IBasicType && s instanceof IBasicType || s instanceof IEnumeration ){ + //4.7 An rvalue of an integer type can be converted to an rvalue of another integer type. + //An rvalue of an enumeration type can be converted to an rvalue of an integer type. + cost.rank = Cost.CONVERSION_RANK; + cost.conversion = 1; + } + + //TODO +// else if( ptr.getType() == ITypeInfo.PtrOp.t_memberPointer ){ +// //4.11-2 An rvalue of type "pointer to member of B of type cv T", where B is a class type, +// //can be converted to an rvalue of type "pointer to member of D of type cv T" where D is a +// //derived class of B +// ITypeInfo.PtrOp srcPtr = trg.hasPtrOperators() ? (ITypeInfo.PtrOp)trg.getPtrOperators().get(0) : null; +// if( trgDecl.isType( srcDecl.getType() ) && srcPtr != null && srcPtr.getType() == ITypeInfo.PtrOp.t_memberPointer ){ +// try { +// temp = hasBaseClass( ptr.getMemberOf(), srcPtr.getMemberOf() ); +// } catch (ParserSymbolTableException e) { +// //not going to happen since we didn't ask for the visibility exception +// } +// cost.rank = ( temp > -1 ) ? Cost.CONVERSION_RANK : Cost.NO_MATCH_RANK; +// cost.detail = 1; +// cost.conversion = ( temp > -1 ) ? temp : 0; +// return; +// } +// } + + } + + static private void derivedToBaseConversion( Cost cost ) { + IType s = getUltimateType( cost.source ); + IType t = getUltimateType( cost.target ); + + if( cost.targetHadReference && s instanceof ICPPClassType && t instanceof ICPPClassType ){ + int temp = hasBaseClass( (ICPPClassType) s, (ICPPClassType) t, true ); + + if( temp > -1 ){ + cost.rank = Cost.DERIVED_TO_BASE_CONVERSION; + cost.conversion = temp; + } + } + } + + static private int hasBaseClass( ICPPClassType symbol, ICPPClassType base, boolean needVisibility ) { + if( symbol == base ){ + return 0; + } + ICPPClassType parent = null; + ICPPBase [] bases = symbol.getBases(); + + for( int i = 0; i < bases.length; i ++ ){ + ICPPBase wrapper = bases[i]; + parent = bases[i].getBaseClass(); + boolean isVisible = ( wrapper.getVisibility() == ICPPBase.v_public); + + if( parent == base ){ + if( needVisibility && !isVisible ) + return -1; + return 1; + } + int n = hasBaseClass( parent, base, needVisibility ); + if( n > 0 ) + return n + 1; + } + return -1; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedef.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedef.java new file mode 100644 index 00000000000..c2e25c97f3b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedef.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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 Dec 11, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; + +/** + * @author aniefer + */ +public class CPPTypedef implements ITypedef { + private IASTDeclarator declarator = null; + /** + * @param declarator + */ + public CPPTypedef(IASTDeclarator declarator) { + this.declarator = declarator; + + // TODO Auto-generated constructor stub + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.ITypedef#getType() + */ + public IType getType() { + IASTSimpleDeclaration decl = (IASTSimpleDeclaration) declarator.getParent(); + return CPPVisitor.createType( decl.getDeclSpecifier() ); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getName() + */ + public String getName() { + return declarator.getName().toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray() + */ + public char[] getNameCharArray() { + return declarator.getName().toCharArray(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getScope() + */ + public IScope getScope() { + return CPPVisitor.getContainingScope( declarator ); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IBinding#getPhysicalNode() + */ + public IASTNode getPhysicalNode() { + return declarator; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java index 499a29dc17c..cb88cd66171 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java @@ -13,8 +13,6 @@ */ package org.eclipse.cdt.internal.core.dom.parser.cpp; -import java.util.ArrayList; -import java.util.List; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; @@ -45,10 +43,13 @@ import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializerList; import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; +import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTPointer; +import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStatement; @@ -58,9 +59,12 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; +import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.c.ICFunctionScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; @@ -69,14 +73,17 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionTryBlockDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; 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.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; @@ -85,6 +92,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypenameExpression; 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.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; @@ -92,12 +100,6 @@ 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.gnu.IGNUASTCompoundStatementExpression; 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.ObjectMap; -import org.eclipse.cdt.core.parser.util.ObjectSet; -import org.eclipse.cdt.internal.core.dom.parser.ASTNode; -import org.eclipse.cdt.internal.core.parser.pst.ISymbol; -import org.eclipse.cdt.internal.core.parser.pst.ITypeInfo; /** * @author aniefer @@ -113,9 +115,11 @@ public class CPPVisitor { parent instanceof ICPPASTQualifiedName || parent instanceof ICPPASTBaseSpecifier ) { - return resolveBinding( name ); + return CPPSemantics.resolveBinding( name ); } else if( parent instanceof IASTIdExpression ){ return resolveBinding( parent ); + } else if( parent instanceof ICPPASTFieldReference ){ + return resolveBinding( parent ); } else if( parent instanceof ICPPASTCompositeTypeSpecifier ){ return createBinding( (ICPPASTCompositeTypeSpecifier) parent ); } else if( parent instanceof IASTDeclarator ){ @@ -132,7 +136,7 @@ public class CPPVisitor { if( parent instanceof IASTSimpleDeclaration ){ IASTDeclarator [] dtors = ((IASTSimpleDeclaration)parent).getDeclarators(); if( dtors.length > 0 ){ - IBinding binding = resolveBinding( elabType.getName() ); + IBinding binding = CPPSemantics.resolveBinding( elabType.getName() ); if( binding != null ) return binding; } @@ -171,7 +175,7 @@ public class CPPVisitor { binding.addDefinition( namespaceDef ); return binding; } else if( declaration instanceof ICPPASTUsingDirective ){ - return resolveBinding( ((ICPPASTUsingDirective) declaration).getQualifiedName() ); + return CPPSemantics.resolveBinding( ((ICPPASTUsingDirective) declaration).getQualifiedName() ); } @@ -189,13 +193,15 @@ public class CPPVisitor { } else { if( parent instanceof IASTSimpleDeclaration ){ IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent; - if( simpleDecl.getParent() instanceof ICPPASTCompositeTypeSpecifier ){ + if( simpleDecl.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef ){ + binding = new CPPTypedef( declarator ); + } else if( simpleDecl.getParent() instanceof ICPPASTCompositeTypeSpecifier ){ binding = new CPPField( declarator ); } else { binding = new CPPVariable( declarator ); } } else if( parent instanceof IASTParameterDeclaration ){ - + binding = new CPPParameter( declarator ); } else if( parent instanceof IASTFunctionDefinition ){ } @@ -240,7 +246,13 @@ public class CPPVisitor { return ((ICPPNamespace)binding).getNamespaceScope(); } } - } + } else if( parent instanceof ICPPASTFieldReference ){ + IASTExpression owner = ((ICPPASTFieldReference)parent).getFieldOwner(); + IType type = CPPSemantics.getUltimateType( getExpressionType( owner ) ); + if( type instanceof ICPPClassType ){ + return ((ICPPClassType) type).getCompositeScope(); + } + } return getContainingScope( parent ); } /** @@ -309,7 +321,7 @@ public class CPPVisitor { return null; } - private static IASTNode getContainingBlockItem( IASTNode node ){ + public static IASTNode getContainingBlockItem( IASTNode node ){ IASTNode parent = node.getParent(); if( parent == null ) return null; @@ -322,7 +334,7 @@ public class CPPVisitor { } else if( parent instanceof IASTExpression ){ IASTNode p = parent.getParent(); if( p instanceof IASTStatement ) - return parent; + return p; } else if ( parent instanceof IASTStatement || parent instanceof IASTTranslationUnit ) { return parent; } @@ -332,499 +344,13 @@ public class CPPVisitor { static private IBinding resolveBinding( IASTNode node ){ if( node instanceof IASTIdExpression ){ - return resolveBinding( ((IASTIdExpression)node).getName() ); + return CPPSemantics.resolveBinding( ((IASTIdExpression)node).getName() ); + } else if( node instanceof ICPPASTFieldReference ){ + return CPPSemantics.resolveBinding( ((ICPPASTFieldReference)node).getFieldName() ); } return null; } - static protected class LookupData - { - public char[] name; - 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 inheritanceChain; //used to detect circular inheritance - - public boolean qualified = false; - public boolean ignoreUsingDirectives = false; - public boolean usingDirectivesOnly = false; - public boolean forDefinition = false; - public boolean typesOnly = false; - public List foundItems = null; - - public LookupData( char[] n ){ - name = n; - } - } - - static private IBinding resolveBinding( IASTName name ){ - //1: get some context info off of the name to figure out what kind of lookup we want - LookupData data = createLookupData( name ); - - //2: lookup - lookup( data, name ); - - //3: resolve ambiguities - IASTName found = resolveAmbiguities( data, name ); - if( found != null ) { - IBinding binding = found.resolveBinding(); - if( binding != null && data.forDefinition ){ - addDefinition( binding, name ); - } - return binding; - } - return null; - } - private static void addDefinition( IBinding binding, IASTName name ){ - if( binding instanceof IFunction ){ - IASTNode node = name.getParent(); - if( node instanceof ICPPASTQualifiedName ) - node = node.getParent(); - if( node instanceof IASTFunctionDeclarator ){ - ((CPPFunction)binding).addDefinition( (IASTFunctionDeclarator) node ); - } - } - } - static private LookupData createLookupData( IASTName name ){ - LookupData data = new LookupData( name.toCharArray() ); - IASTNode parent = name.getParent(); - if( parent instanceof ICPPASTQualifiedName ){ - data.qualified = ((ICPPASTQualifiedName)parent).getNames()[0] != name; - parent = parent.getParent(); - if( parent instanceof IASTDeclarator ){ - data.forDefinition = true; - } - } else if( parent instanceof IASTDeclarator ){ - data.forDefinition = true; - } else if ( parent instanceof ICPPASTBaseSpecifier || - parent instanceof ICPPASTElaboratedTypeSpecifier) - { - data.typesOnly = true; - } - return data; - } - - static private IASTName resolveAmbiguities( LookupData data, IASTName name ) { - if( data.foundItems == null || data.foundItems.size() == 0 ) - return null; - - if( data.foundItems.size() == 1 ){ - return (IASTName) data.foundItems.get(0); - } - - IASTName type = null; - IASTName obj = null; - for( int i = 0; i < data.foundItems.size(); i++ ){ - IASTName n = (IASTName) data.foundItems.get( i ); - IASTNode parent = n.getParent(); - if( parent instanceof IASTDeclarator ){ - if( obj == null ){ - obj = n; - } else { - //TODO - } - } else if( parent instanceof ICPPASTElaboratedTypeSpecifier || - parent instanceof IASTEnumerationSpecifier || - parent instanceof ICPPASTCompositeTypeSpecifier ) - { - if( type == null ){ - type = n; - } else { - //TODO - } - } - } - - if( type != null ) { - if( obj != null ){ - if( obj.resolveBinding().getScope() != type.resolveBinding().getScope() ){ - return null; //ambiguous - } - } else { - return type; - } - } - return obj; - } - static private IASTName collectResult( LookupData data, IASTNode node, boolean checkAux ){ - IASTDeclaration declaration = null; - if( node instanceof IASTDeclaration ) - declaration = (IASTDeclaration) node; - if( declaration instanceof IASTDeclarationStatement ) - declaration = ((IASTDeclarationStatement)node).getDeclaration(); - else if( declaration instanceof IASTForStatement ) - declaration = ((IASTForStatement)node).getInitDeclaration(); - - if( declaration == null ) - return null; - - if( declaration instanceof IASTSimpleDeclaration ){ - IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration; - if( !data.typesOnly ) { - IASTDeclarator [] declarators = simpleDeclaration.getDeclarators(); - for( int i = 0; i < declarators.length; i++ ){ - IASTDeclarator declarator = declarators[i]; - IASTName declaratorName = declarator.getName(); - if( CharArrayUtils.equals( declaratorName.toCharArray(), data.name ) ){ - return declaratorName; - } - } - } - - //decl spec - IASTDeclSpecifier declSpec = simpleDeclaration.getDeclSpecifier(); - if( declSpec instanceof IASTElaboratedTypeSpecifier ){ - IASTName elabName = ((IASTElaboratedTypeSpecifier)declSpec).getName(); - if( CharArrayUtils.equals( elabName.toCharArray(), data.name ) ){ - return elabName; - } - } else if( declSpec instanceof ICPPASTCompositeTypeSpecifier ){ - IASTName compName = ((IASTCompositeTypeSpecifier)declSpec).getName(); - if( CharArrayUtils.equals( compName.toCharArray(), data.name ) ){ - return compName; - } - } else if( declSpec instanceof IASTEnumerationSpecifier ){ - IASTEnumerationSpecifier enumeration = (IASTEnumerationSpecifier) declSpec; - IASTName eName = enumeration.getName(); - if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ - return eName; - } - if( !data.typesOnly ) { - //check enumerators too - IASTEnumerator [] list = enumeration.getEnumerators(); - for( int i = 0; i < list.length; i++ ) { - IASTEnumerator enumerator = list[i]; - if( enumerator == null ) break; - eName = enumerator.getName(); - if( CharArrayUtils.equals( eName.toCharArray(), data.name ) ){ - return eName; - } - } - } - } - } - if( data.typesOnly ) - return null; - - if( declaration instanceof IASTFunctionDefinition ){ - IASTFunctionDefinition functionDef = (IASTFunctionDefinition) declaration; - IASTFunctionDeclarator declarator = functionDef.getDeclarator(); - - //check the function itself - IASTName declName = declarator.getName(); - if( declName instanceof ICPPASTQualifiedName ){ - IASTName [] names = ((ICPPASTQualifiedName)declName).getNames(); - declName = names[ names.length - 1 ]; - } - if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ - return declName; - } - if( checkAux ) { - //check the parameters - IASTParameterDeclaration [] parameters = declarator.getParameters(); - for( int i = 0; i < parameters.length; i++ ){ - IASTParameterDeclaration parameterDeclaration = parameters[i]; - if( parameterDeclaration == null ) break; - declName = parameterDeclaration.getDeclarator().getName(); - if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){ - return declName; - } - } - } - } else if( declaration instanceof ICPPASTNamespaceDefinition ){ - IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName(); - if( CharArrayUtils.equals( namespaceName.toCharArray(), data.name ) ) - return namespaceName; - } - - return null; - } - static private void lookup( LookupData data, IASTName name ){ - IASTNode node = name; - - ICPPScope scope = (ICPPScope) getContainingScope( node ); - while( scope != null ){ - IASTNode blockItem = getContainingBlockItem( node ); - if( scope.getPhysicalNode() != blockItem.getParent() ) - blockItem = node; - - List directives = null; - if( !data.usingDirectivesOnly ){ - directives = new ArrayList(2); - data.foundItems = lookupInScope( data, scope, blockItem, directives ); - } - - - if( !data.ignoreUsingDirectives ) { - data.visited.clear(); - if( data.foundItems == null || data.foundItems.isEmpty() ){ - List transitives = lookupInNominated( data, scope, null ); - - processDirectives( data, scope, transitives ); - if( directives != null && directives.size() != 0 ) - processDirectives( data, scope, directives ); - - while( !data.usingDirectives.isEmpty() && data.usingDirectives.get( scope ) != null ){ - if( transitives != null ) - transitives.clear(); - transitives = lookupInNominated( data, scope, transitives ); - - if( !data.qualified || data.foundItems == null ){ - processDirectives( data, scope, transitives ); - } - } - } - } - - if( data.foundItems != null && !data.foundItems.isEmpty() ) - return; - - if( !data.usingDirectivesOnly && scope instanceof ICPPClassScope ){ - data.foundItems = lookupInParents( data, (ICPPClassScope) scope ); - } - - if( data.foundItems != null && !data.foundItems.isEmpty() ) - return; - - //if still not found, loop and check our containing scope - if( data.qualified && !data.usingDirectives.isEmpty() ) - data.usingDirectivesOnly = true; - - if( blockItem != null ) - node = blockItem; - scope = (ICPPScope) scope.getParent(); - } - } - - private static List lookupInParents( LookupData data, ICPPClassScope lookIn ){ - ICPPASTCompositeTypeSpecifier compositeTypeSpec = (ICPPASTCompositeTypeSpecifier) lookIn.getPhysicalNode(); - ICPPASTBaseSpecifier [] bases = compositeTypeSpec.getBaseSpecifiers(); - - List inherited = null; - List result = null; - - if( bases.length == 0 ) - return null; - - //use data to detect circular inheritance - if( data.inheritanceChain == null ) - data.inheritanceChain = new ObjectSet( 2 ); - - data.inheritanceChain.put( lookIn ); - - int size = bases.length; - for( int i = 0; i < size; i++ ) - { - ICPPClassType binding = (ICPPClassType) bases[i].getName().resolveBinding(); - ICPPClassScope parent = (ICPPClassScope) binding.getCompositeScope(); - - if( parent == null ) - continue; - - if( !bases[i].isVirtual() || !data.visited.containsKey( parent ) ){ - if( bases[i].isVirtual() ){ - if( data.visited == ObjectSet.EMPTY_SET ) - data.visited = new ObjectSet(2); - data.visited.put( parent ); - } - - //if the inheritanceChain already contains the parent, then that - //is circular inheritance - if( ! data.inheritanceChain.containsKey( parent ) ){ - //is this name define in this scope? - inherited = lookupInScope( data, parent, null, null ); - - if( inherited == null || inherited.isEmpty() ){ - inherited = lookupInParents( data, parent ); - } - } else { - //throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance ); - } - } - - if( inherited != null && !inherited.isEmpty() ){ - if( result == null || result.isEmpty() ){ - result = inherited; - } else if ( inherited != null && !inherited.isEmpty() ) { - for( int j = 0; j < result.size(); j++ ) { - IASTName n = (IASTName) result.get(j); - if( !checkAmbiguity( n, inherited ) ){ - //throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); - return null; - } - } - } - } else { - inherited = null; //reset temp for next iteration - } - } - - data.inheritanceChain.remove( lookIn ); - - return result; - } - - private static boolean checkAmbiguity( Object obj1, Object obj2 ){ - //it is not ambiguous if they are the same thing and it is static or an enumerator - if( obj1 == obj2 ){ - List objList = ( obj1 instanceof List ) ? (List) obj1 : null; - int objListSize = ( objList != null ) ? objList.size() : 0; - ISymbol symbol = ( objList != null ) ? (ISymbol) objList.get(0) : ( ISymbol )obj1; - int idx = 1; - while( symbol != null ) { - ITypeInfo type = ((ISymbol)obj1).getTypeInfo(); - if( !type.checkBit( ITypeInfo.isStatic ) && !type.isType( ITypeInfo.t_enumerator ) ){ - return false; - } - - if( objList != null && idx < objListSize ){ - symbol = (ISymbol) objList.get( idx++ ); - } else { - symbol = null; - } - } - return true; - } - return false; - } - static private void processDirectives( LookupData data, IScope scope, List directives ){ - if( directives == null || directives.size() == 0 ) - return; - - ICPPScope enclosing = null; - IScope temp = null; - - int size = directives.size(); - for( int i = 0; i < size; i++ ){ - IASTName qualName = ((ICPPASTUsingDirective)directives.get(i)).getQualifiedName(); - IBinding binding = qualName.resolveBinding(); - if( binding instanceof ICPPNamespace ){ - temp = ((ICPPNamespace)binding).getNamespaceScope(); - } else - continue; - - //namespace are searched at most once - if( !data.visited.containsKey( temp ) ){ - enclosing = getClosestEnclosingScope( scope, temp ); - - //data.usingDirectives is a map from enclosing scope to a list - //of namespaces to consider when we reach that enclosing scope - List list = data.usingDirectives.isEmpty() ? null : (List) data.usingDirectives.get( enclosing ); - if( list == null ){ - list = new ArrayList(); - - if( data.usingDirectives == ObjectMap.EMPTY_MAP ){ - data.usingDirectives = new ObjectMap(2); - } - data.usingDirectives.put( enclosing, list ); - } - list.add( temp ); - } - } - - } - static private ICPPScope getClosestEnclosingScope( IScope scope1, IScope scope2 ){ - ObjectSet set = new ObjectSet( 2 ); - IScope parent = scope1; - while( parent != null ){ - set.put( parent ); - parent = parent.getParent(); - } - parent = scope2; - while( parent != null && !set.containsKey( parent ) ){ - parent = parent.getParent(); - } - return (ICPPScope) parent; - } - /** - * - * @param scope - * @return List of encountered using directives - */ - static private List lookupInScope( LookupData data, ICPPScope scope, IASTNode blockItem, List usingDirectives ) { - IASTName possible = null; - IASTNode [] nodes = null; - IASTNode parent = scope.getPhysicalNode(); - - List found = null; - - if( parent instanceof IASTCompoundStatement ){ - IASTCompoundStatement compound = (IASTCompoundStatement) parent; - nodes = compound.getStatements(); - } else if ( parent instanceof IASTTranslationUnit ){ - IASTTranslationUnit translation = (IASTTranslationUnit) parent; - nodes = translation.getDeclarations(); - } else if ( parent instanceof ICPPASTCompositeTypeSpecifier ){ - ICPPASTCompositeTypeSpecifier comp = (ICPPASTCompositeTypeSpecifier) parent; - nodes = comp.getMembers(); - } else if ( parent instanceof ICPPASTNamespaceDefinition ){ - nodes = ((ICPPASTNamespaceDefinition)parent).getDeclarations(); - } - - int idx = -1; - IASTNode item = ( nodes != null ? (nodes.length > 0 ? nodes[++idx] : null ) : parent ); - - while( item != null ) { - if( item == null || item == blockItem || ( blockItem != null && ((ASTNode)item).getOffset() > ((ASTNode) blockItem).getOffset() )) - break; - - if( item instanceof ICPPASTUsingDirective && !data.ignoreUsingDirectives ) { - if( usingDirectives != null ) - usingDirectives.add( item ); - } else { - possible = collectResult( data, item, (item == parent) ); - if( possible != null ){ - if( found == null ) - found = new ArrayList(2); - found.add( possible ); - } - } - if( idx > -1 && ++idx < nodes.length ){ - item = nodes[idx]; - } else { - item = null; - } - } - return found; - } - - static private List lookupInNominated( LookupData data, ICPPScope scope, List transitives ){ - if( data.usingDirectives.isEmpty() ) - return transitives; - - List directives = null; - ICPPScope temp = null; - - directives = (List) data.usingDirectives.remove( scope ); - if( directives == null || directives.size() == 0 ) { - return transitives; - } - for( int i = 0; i < directives.size(); i++ ){ - temp = (ICPPScope) directives.get(i); - if( !data.visited.containsKey( temp ) ){ - if( data.visited == ObjectSet.EMPTY_SET ) { - data.visited = new ObjectSet(2); - } - data.visited.put( temp ); - List usings = new ArrayList(2); - List found = lookupInScope( data, temp, null, usings ); - if( data.foundItems == null ) - data.foundItems = found; - else if( found != null ) - data.foundItems.addAll( found ); - - - //only consider the transitive using directives if we are an unqualified - //lookup, or we didn't find the name in decl - if( usings != null && usings.size() > 0 && (!data.qualified || found == null ) ){ - if( transitives == null ) - transitives = new ArrayList(2); - transitives.addAll( usings ); - } - } - } - return transitives; - } - public static abstract class CPPBaseVisitorAction { public boolean processNames = false; public boolean processDeclarations = false; @@ -995,12 +521,12 @@ public class CPPVisitor { if( !visitDeclarator( param.getDeclarator(), action ) ) return false; } ICPPASTConstructorChainInitializer [] ctorChain = fdtor.getConstructorChain(); - for( int i = 0; i < list.length; i++ ){ + for( int i = 0; i < ctorChain.length; i++ ){ if( !visitName( ctorChain[i].getMemberInitializerId(), action ) ) return false; if( !visitExpression( ctorChain[i].getInitializerValue(), action ) ) return false; } IASTTypeId [] typeIds = fdtor.getExceptionSpecification(); - for( int i = 0; i < list.length; i++ ){ + for( int i = 0; i < typeIds.length; i++ ){ if( !visitTypeId( typeIds[i], action ) ) return false; } @@ -1218,4 +744,91 @@ public class CPPVisitor { public static boolean visitTemplateParameter(ICPPASTTemplateParameter parameter, CPPBaseVisitorAction action) { return true; } + + /** + * @param declarator + * @return + */ + public static IType createType(IASTDeclarator declarator) { + IASTNode parent = declarator.getParent(); + IASTDeclSpecifier declSpec = null; + if( parent instanceof IASTParameterDeclaration ) + declSpec = ((IASTParameterDeclaration) parent).getDeclSpecifier(); + else if( parent instanceof IASTSimpleDeclaration ) + declSpec = ((IASTSimpleDeclaration)parent).getDeclSpecifier(); + + IType type = createType( declSpec ); + + IASTPointerOperator [] ptrOps = declarator.getPointerOperators(); + for( int i = ptrOps.length - 1; i >= 0; i-- ){ + type = new CPPPointerType( type, (IASTPointer) ptrOps[i] ); + } + return type; + } + + /** + * @param declSpec + * @return + */ + protected static IType createType(IASTDeclSpecifier declSpec) { + if( declSpec instanceof ICPPASTCompositeTypeSpecifier ){ + IBinding binding = ((ICPPASTCompositeTypeSpecifier) declSpec).getName().resolveBinding(); + if( binding instanceof IType) + return (IType) binding; + } else if( declSpec instanceof ICPPASTElaboratedTypeSpecifier ){ + IBinding binding = ((ICPPASTElaboratedTypeSpecifier)declSpec).getName().resolveBinding(); + if( binding instanceof IType ) + return (IType) binding; + } else if( declSpec instanceof ICPPASTSimpleDeclSpecifier ){ + ICPPASTSimpleDeclSpecifier spec = (ICPPASTSimpleDeclSpecifier) declSpec; + int bits = ( spec.isLong() ? CPPBasicType.IS_LONG : 0 ) & + ( spec.isShort() ? CPPBasicType.IS_SHORT : 0 ) & + ( spec.isSigned() ? CPPBasicType.IS_SIGNED: 0 ) & + ( spec.isUnsigned() ? CPPBasicType.IS_SHORT : 0 ); + if( spec instanceof IGPPASTSimpleDeclSpecifier ){ + IGPPASTSimpleDeclSpecifier gspec = (IGPPASTSimpleDeclSpecifier) spec; + bits &= ( gspec.isLongLong() ? GPPBasicType.IS_LONGLONG : 0 ); + return new GPPBasicType( spec.getType(), bits, getExpressionType(gspec.getTypeofExpression()) ); + } + return new CPPBasicType( spec.getType(), bits ); + + } + return null; + } + + /** + * @param expression + * @return + */ + public static IType getExpressionType(IASTExpression expression) { + if( expression == null ) + return null; + if( expression instanceof IASTIdExpression ){ + IBinding binding = resolveBinding( expression ); + if( binding instanceof IVariable ){ + return ((IVariable)binding).getType(); + } + } else if( expression instanceof IASTCastExpression ){ + IASTTypeId id = ((IASTCastExpression)expression).getTypeId(); + return createType( id.getAbstractDeclarator() ); + } else if( expression instanceof ICPPASTLiteralExpression ){ + switch( ((ICPPASTLiteralExpression) expression).getKind() ){ + case ICPPASTLiteralExpression.lk_this : break; + case ICPPASTLiteralExpression.lk_true : + case ICPPASTLiteralExpression.lk_false: + return new CPPBasicType( ICPPBasicType.t_bool, 0 ); + case IASTLiteralExpression.lk_char_constant: + return new CPPBasicType( IBasicType.t_char, 0 ); + case IASTLiteralExpression.lk_float_constant: + return new CPPBasicType( IBasicType.t_float, 0 ); + case IASTLiteralExpression.lk_integer_constant: + return new CPPBasicType( IBasicType.t_int, 0 ); + case IASTLiteralExpression.lk_string_literal: + IType type = new CPPBasicType( IBasicType.t_char, 0 ); + return new CPPPointerType( type ); + } + + } + return null; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 2ba2ba18714..4b2524c44c2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -1462,7 +1462,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { firstExpression.setPropertyInParent( IASTFunctionCallExpression.FUNCTION_NAME ); if( secondExpression != null ) { - fce.setFunctionNameExpression( secondExpression ); + fce.setParameterExpression( secondExpression ); secondExpression.setParent( fce ); secondExpression.setPropertyInParent( IASTFunctionCallExpression.PARAMETERS ); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GPPBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GPPBasicType.java new file mode 100644 index 00000000000..4be8f9fe5c8 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GPPBasicType.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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 Dec 10, 2004 + */ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTSimpleDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPBasicType; + +/** + * @author aniefer + */ +public class GPPBasicType extends CPPBasicType implements IGPPBasicType { + public static final int IS_LONGLONG = LAST << 1; + + private IType typeOf; + + public GPPBasicType( int type, int bits, IType typeOf ){ + super( type, bits ); + this.typeOf = typeOf; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPBasicType#isLongLong() + */ + public boolean isLongLong() { + return ( qualifierBits & IS_LONGLONG ) != 0; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPBasicType#getTypeofType() + */ + public IType getTypeofType() { + if( type != IGPPASTSimpleDeclSpecifier.t_typeof ) + return null; + return typeOf; + } + +}