blob: 891b65e8874f3eca8c052772c9c5f4fd6cb76d38 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05. html
*
* Contributors:
* Rational Software - Initial API and implementation
*
***********************************************************************/
package org.eclipse.cdt.internal.core.parser.pst;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.parser.Enum;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.core.parser.ast.IASTMember;
import org.eclipse.cdt.core.parser.ast.IASTNode;
import org.eclipse.cdt.internal.core.parser.pst.IDerivableContainerSymbol.IParentSymbol;
import org.eclipse.cdt.internal.core.parser.pst.TypeInfo.PtrOp;
/**
* @author aniefer
*/
public class ParserSymbolTable {
public static final String EMPTY_NAME = ""; //$NON-NLS-1$
public static final String THIS = "this"; //$NON-NLS-1$
/**
* Constructor for ParserSymbolTable.
*/
public ParserSymbolTable( ParserLanguage language ) {
super();
_compilationUnit = newContainerSymbol( EMPTY_NAME, TypeInfo.t_namespace );
_language = language;
}
public IContainerSymbol getCompilationUnit(){
return _compilationUnit;
}
public IContainerSymbol newContainerSymbol( String name ){
return new ContainerSymbol( this, name );
}
public IContainerSymbol newContainerSymbol( String name, TypeInfo.eType type ){
return new ContainerSymbol( this, name, type );
}
public ISymbol newSymbol( String name ){
return new BasicSymbol( this, name );
}
public ISymbol newSymbol( String name, TypeInfo.eType type ){
return new BasicSymbol( this, name, type );
}
public IDerivableContainerSymbol newDerivableContainerSymbol( String name ){
return new DerivableContainerSymbol( this, name );
}
public IDerivableContainerSymbol newDerivableContainerSymbol( String name, TypeInfo.eType type ){
return new DerivableContainerSymbol( this, name, type );
}
public IParameterizedSymbol newParameterizedSymbol( String name ){
return new ParameterizedSymbol( this, name );
}
public IParameterizedSymbol newParameterizedSymbol( String name, TypeInfo.eType type ){
return new ParameterizedSymbol( this, name, type );
}
public ISpecializedSymbol newSpecializedSymbol( String name ){
return new SpecializedSymbol( this, name );
}
// public ISpecializedSymbol newSpecializedSymbol( String name, TypeInfo.eType type ){
// return new Declaration( this, name, type );
// }
/**
* Lookup the name from LookupData starting in the inDeclaration
* @param data
* @param inDeclaration
* @return Declaration
* @throws ParserSymbolTableException
*/
static protected void lookup( LookupData data, IContainerSymbol inSymbol ) throws ParserSymbolTableException
{
// if( data.type != TypeInfo.t_any && data.type.compareTo(TypeInfo.t_class) < 0 && data.upperType.compareTo(TypeInfo.t_union) > 0 ){
// throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
// }
//handle namespace aliases
if( inSymbol.isType( TypeInfo.t_namespace ) ){
ISymbol symbol = inSymbol.getTypeSymbol();
if( symbol != null && symbol.isType( TypeInfo.t_namespace ) ){
inSymbol = (IContainerSymbol) symbol;
}
}
ISymbol symbol = null; //the return value
LinkedList transitives = new LinkedList(); //list of transitive using directives
//if this name define in this scope?
Map map = null;
if( !data.usingDirectivesOnly ){
map = lookupInContained( data, inSymbol );
if( data.foundItems == null || data.foundItems.isEmpty() ){
data.foundItems = map;
} else {
mergeResults( data, data.foundItems, map );
}
}
if( inSymbol.getSymbolTable().getLanguage() == ParserLanguage.CPP &&
!data.ignoreUsingDirectives )
{
//check nominated namespaces
//the transitives list is populated in LookupInNominated, and then
//processed in ProcessDirectives
data.visited.clear(); //each namesapce is searched at most once, so keep track
lookupInNominated( data, inSymbol, transitives );
//if we are doing a qualified lookup, only process using directives if
//we haven't found the name yet (and if we aren't ignoring them).
if( !data.qualified || data.foundItems == null || data.foundItems.isEmpty() ){
processDirectives( inSymbol, data, transitives );
if( inSymbol.hasUsingDirectives() ){
processDirectives( inSymbol, data, inSymbol.getUsingDirectives() );
}
while( data.usingDirectives != null && data.usingDirectives.get( inSymbol ) != null ){
transitives.clear();
lookupInNominated( data, inSymbol, transitives );
if( !data.qualified || data.foundItems == null ){
processDirectives( inSymbol, data, transitives );
}
}
}
}
if( data.mode == LookupMode.NORMAL && ( !data.foundItems.isEmpty() || data.stopAt == inSymbol ) ){
return;
}
if( !data.usingDirectivesOnly && inSymbol instanceof IDerivableContainerSymbol ){
//if we still havn't found it, check any parents we have
data.visited.clear(); //each virtual base class is searched at most once
map = lookupInParents( data, (IDerivableContainerSymbol)inSymbol );
if( data.foundItems == null || data.foundItems.isEmpty() ){
data.foundItems = map;
} else {
mergeInheritedResults( data.foundItems, map );
}
}
//if still not found, check our containing scope.
if( ( data.foundItems == null || data.foundItems.isEmpty() || data.mode == LookupMode.PREFIX )
&& inSymbol.getContainingSymbol() != null )
{
if( data.qualified ){
if( data.usingDirectives != null && !data.usingDirectives.isEmpty() ){
data.usingDirectivesOnly = true;
lookup( data, inSymbol.getContainingSymbol() );
}
} else {
lookup( data, inSymbol.getContainingSymbol() );
}
}
return;
}
/**
* function LookupInNominated
* @param data
* @param transitiveDirectives
* @return List
*
* for qualified:
* 3.4.3.2-2 "let S be the set of all declarations of m in X
* and in the transitive closure of all namespaces nominated by using-
* directives in X and its used namespaces, except that using-directives are
* ignored in any namespace, including X, directly containing one or more
* declarations of m."
*
* for unqualified:
* 7.3.4-2 The using-directive is transitive: if a scope contains a using
* directive that nominates a second namespace that itself contains using-
* directives, the effect is as if the using-directives from the second
* namespace also appeared in the first.
*/
static private void lookupInNominated( LookupData data, IContainerSymbol symbol, LinkedList transitiveDirectives ) throws ParserSymbolTableException{
//if the data.usingDirectives is empty, there is nothing to do.
if( data.usingDirectives == null ){
return;
}
//local variables
LinkedList directives = null; //using directives association with declaration
Iterator iter = null;
IContainerSymbol temp = null;
boolean foundSomething = false;
int size = 0;
directives = (LinkedList) data.usingDirectives.remove( symbol );
if( directives == null ){
return;
}
iter = directives.iterator();
size = directives.size();
for( int i = size; i > 0; i-- ){
temp = (IContainerSymbol) iter.next();
//namespaces are searched at most once
if( !data.visited.contains( temp ) ){
data.visited.add( temp );
Map map = lookupInContained( data, temp );
foundSomething = !map.isEmpty();
mergeResults( data, data.foundItems, map );
//only consider the transitive using directives if we are an unqualified
//lookup, or we didn't find the name in decl
if( (!data.qualified || !foundSomething || data.mode == LookupMode.PREFIX ) && temp.getUsingDirectives() != null ){
//name wasn't found, add transitive using directives for later consideration
transitiveDirectives.addAll( temp.getUsingDirectives() );
}
}
}
return;
}
/**
* @param map
* @param map2
*/
private static void mergeResults( LookupData data, Map resultMap, Map map ) throws ParserSymbolTableException {
if( resultMap == null || map == null || map.isEmpty() ){
return;
}
Iterator keyIterator = map.keySet().iterator();
Object key = null;
while( keyIterator.hasNext() ){
key = keyIterator.next();
if( resultMap.containsKey( key ) ){
List list = new LinkedList();
Object obj = resultMap.get( key );
if ( obj instanceof List ) list.addAll( (List) obj );
else list.add( obj );
obj = map.get( key );
if( obj instanceof List ) list.addAll( (List) obj );
else list.add( obj );
resultMap.put( key, collectSymbol( data, list ) );
} else {
resultMap.put( key, map.get( key ) );
}
}
}
/**
* function LookupInContained
* @param data
* @return List
*
* Look for data.name in our collection _containedDeclarations
*/
protected static Map lookupInContained( LookupData data, IContainerSymbol lookIn ) throws ParserSymbolTableException{
Map found = new LinkedHashMap();
boolean foundSomething = false;
ISymbol temp = null;
Object obj = null;
if( data.associated != null ){
//we are looking in lookIn, remove it from the associated scopes list
data.associated.remove( lookIn );
}
Map declarations = lookIn.getContainedSymbols();
Iterator iterator = ( data.mode == LookupMode.PREFIX ) ? declarations.keySet().iterator() : null;
String name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name;
while( name != null ) {
if( nameMatches( data, name ) ){
obj = ( declarations != null ) ? declarations.get( name ) : null;
obj = collectSymbol( data, obj );
if( obj != null )
found.put( name, obj );
}
if( iterator != null && iterator.hasNext() ){
name = (String) iterator.next();
} else {
name = null;
}
}
if( !found.isEmpty() && data.mode == LookupMode.NORMAL ){
return found;
}
if( lookIn instanceof IParameterizedSymbol ){
Map parameters = ((IParameterizedSymbol)lookIn).getParameterMap();
if( parameters != null ){
iterator = ( data.mode == LookupMode.PREFIX ) ? parameters.keySet().iterator() : null;
name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name;
while( name != null ){
if( nameMatches( data, name ) ){
obj = parameters.get( name );
obj = collectSymbol( data, obj );
if( obj != null ){
found.put( name, obj );
}
}
if( iterator != null && iterator.hasNext() ){
name = (String) iterator.next();
} else {
name = null;
}
}
}
}
return found;
}
private static boolean nameMatches( LookupData data, String name ){
if( data.mode == LookupMode.PREFIX ){
return name.regionMatches( true, 0, data.name, 0, data.name.length() );
} else {
return name.equals( data.name );
}
}
private static boolean checkType( LookupData data, ISymbol symbol ) { //, TypeInfo.eType type, TypeInfo.eType upperType ){
if( data.filter == null ){
return true;
}
if( data.templateInstance != null && symbol.isTemplateMember() ){
if( symbol.isType( TypeInfo.t_type ) ){
symbol = symbol.getTypeSymbol();
}
if( symbol.isType( TypeInfo.t_undef ) && symbol.getContainingSymbol().isType( TypeInfo.t_template ) ){
TypeInfo info = (TypeInfo) data.templateInstance.getArgumentMap().get( symbol );
return data.filter.shouldAccept( symbol, info );
}
}
return data.filter.shouldAccept( symbol );
}
private static Object collectSymbol(LookupData data, Object object ) throws ParserSymbolTableException {
if( object == null ){
return null;
}
ISymbol foundSymbol = null;
Iterator iter = ( object instanceof List ) ? ((List)object).iterator() : null;
ISymbol symbol = ( iter != null ) ? (ISymbol) iter.next() : (ISymbol) object;
Set functionSet = new HashSet();
ISymbol obj = null;
IContainerSymbol cls = null;
while( symbol != null ){
if( !symbol.getIsInvisible() && checkType( data, symbol ) ){//, data.type, data.upperType ) ){
if( symbol.isTemplateMember() && data.templateInstance != null )
foundSymbol = new TemplateInstance( symbol.getSymbolTable(), symbol, data.templateInstance.getArgumentMap() );
else
foundSymbol = symbol;
if( foundSymbol.isType( TypeInfo.t_function ) ){
if( foundSymbol.isForwardDeclaration() && foundSymbol.getTypeSymbol() != null ){
foundSymbol = foundSymbol.getTypeSymbol();
}
functionSet.add( foundSymbol );
} else {
//if this is a class-name, other stuff hides it
if( foundSymbol.isType( TypeInfo.t_class, TypeInfo.t_enumeration ) ){
if( cls == null ){
cls = (IContainerSymbol) foundSymbol;
} else {
if( cls.getTypeInfo().isForwardDeclaration() && cls.getTypeSymbol() == foundSymbol ){
//cls is a forward declaration of decl, we want decl.
cls = (IContainerSymbol) foundSymbol;
} else if( foundSymbol.getTypeInfo().isForwardDeclaration() && foundSymbol.getTypeSymbol() == cls ){
//decl is a forward declaration of cls, we already have what we want (cls)
} else {
if( data.mode == LookupMode.PREFIX ){
if( data.ambiguities == null ){
data.ambiguities = new HashSet();
}
data.ambiguities.add( foundSymbol.getName() );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
}
}
} else {
//an object, can only have one of these
if( obj == null ){
obj = foundSymbol;
} else {
if( data.mode == LookupMode.PREFIX ){
if( data.ambiguities == null ){
data.ambiguities = new HashSet();
}
data.ambiguities.add( foundSymbol.getName() );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
}
}
}
}
if( iter != null ){
symbol = iter.hasNext() ? (ISymbol) iter.next() : null;
} else {
symbol = null;
}
}
int numFunctions = functionSet.size();
boolean ambiguous = false;
if( cls != null ){
//the class is only hidden by other stuff if they are from the same scope
if( obj != null && cls.getContainingSymbol() != obj.getContainingSymbol()){
ambiguous = true;
}
if( !functionSet.isEmpty() ){
Iterator fnIter = functionSet.iterator();
IParameterizedSymbol fn = null;
for( int i = numFunctions; i > 0; i-- ){
fn = (IParameterizedSymbol) fnIter.next();
if( cls.getContainingSymbol()!= fn.getContainingSymbol()){
ambiguous = true;
break;
}
}
}
}
if( obj != null && !ambiguous ){
if( numFunctions > 0 ){
ambiguous = true;
} else {
return obj;
}
} else if( numFunctions > 0 ) {
return new LinkedList( functionSet );
}
if( ambiguous ){
if( data.mode == LookupMode.PREFIX ){
if( data.ambiguities == null ){
data.ambiguities = new HashSet();
}
data.ambiguities.add( foundSymbol.getName() );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
}
return cls;
}
/**
*
* @param data
* @param lookIn
* @return Declaration
* @throws ParserSymbolTableException
*/
private static Map lookupInParents( LookupData data, ISymbol lookIn ) throws ParserSymbolTableException{
IDerivableContainerSymbol container = null;
/*if( lookIn instanceof TemplateInstance ){
} else*/
if( lookIn instanceof IDerivableContainerSymbol ){
container = (IDerivableContainerSymbol) lookIn;
} else{
throw new ParserSymbolTableException( ParserSymbolTableException.r_InternalError );
}
List scopes = container.getParents();
Map temp = null;
Map symbol = null;
Map inherited = null;
Iterator iterator = null;
IDerivableContainerSymbol.IParentSymbol wrapper = null;
if( scopes == null )
return null;
//use data to detect circular inheritance
if( data.inheritanceChain == null )
data.inheritanceChain = new HashSet();
data.inheritanceChain.add( container );
iterator = scopes.iterator();
int size = scopes.size();
for( int i = size; i > 0; i-- )
{
wrapper = (IDerivableContainerSymbol.IParentSymbol) iterator.next();
ISymbol parent = wrapper.getParent();
if( parent.isType( TypeInfo.t_undef ) && parent.getContainingSymbol().isType( TypeInfo.t_template ) ){
TypeInfo info = (TypeInfo) data.templateInstance.getArgumentMap().get( parent );
if( info.getTypeSymbol() instanceof IDerivableContainerSymbol ){
parent = (IDerivableContainerSymbol) info.getTypeSymbol();
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate );
}
}
if( !wrapper.isVirtual() || !data.visited.contains( parent ) ){
if( wrapper.isVirtual() ){
data.visited.add( parent );
}
//if the inheritanceChain already contains the parent, then that
//is circular inheritance
if( ! data.inheritanceChain.contains( parent ) ){
//is this name define in this scope?
if( parent instanceof TemplateInstance ){
ISymbol tempInstance = data.templateInstance;
data.templateInstance = (TemplateInstance) parent;
ISymbol instance = ((TemplateInstance)parent).getInstantiatedSymbol();
if( instance instanceof IContainerSymbol )
temp = lookupInContained( data, (IContainerSymbol)instance );
else
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate );
data.templateInstance = tempInstance;
} else if( parent instanceof IDerivableContainerSymbol ){
temp = lookupInContained( data, (IDerivableContainerSymbol) parent );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
}
if( temp.isEmpty() || data.mode == LookupMode.PREFIX ){
inherited = lookupInParents( data, parent );
mergeInheritedResults( temp, inherited );
}
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance );
}
}
if( temp != null && !temp.isEmpty() ){
if( symbol == null || symbol.isEmpty() ){
symbol = temp;
} else if ( temp != null && !temp.isEmpty() ) {
Iterator iter = temp.keySet().iterator();
Object key = null;
while( iter.hasNext() ){
key = iter.next();
if( symbol.containsKey( key ) ){
ISymbol sym = (ISymbol) symbol.get( key );
if( !checkAmbiguity( sym, temp.get( key ) ) ){
if( data.mode == LookupMode.PREFIX ){
if( data.ambiguities == null ){
data.ambiguities = new HashSet();
}
data.ambiguities.add( sym.getName() );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
}
} else {
symbol.put( key, temp.get( key ) );
}
}
}
} else {
temp = null; //reset temp for next iteration
}
}
data.inheritanceChain.remove( container );
return symbol;
}
private static boolean checkAmbiguity( Object obj1, Object obj2 ) throws ParserSymbolTableException{
//it is not ambiguous if they are the same thing and it is static or an enumerator
if( obj1 == obj2 ){
Iterator iter = ( obj1 instanceof List ) ? ((List) obj1).iterator() : null;
ISymbol symbol = ( iter != null ) ? (ISymbol) iter.next() : ( ISymbol )obj1;
while( symbol != null ) {
TypeInfo type = ((ISymbol)obj1).getTypeInfo();
if( !type.checkBit( TypeInfo.isStatic ) && !type.isType( TypeInfo.t_enumerator ) ){
return false;
}
if( iter != null && iter.hasNext() ){
symbol = (ISymbol) iter.next();
} else {
symbol = null;
}
}
return true;
}
return false;
}
/**
* Symbols in map are added to the resultMap if a symbol with that name does not already exist there
* @param resultMap
* @param map
* @throws ParserSymbolTableException
*/
private static void mergeInheritedResults( Map resultMap, Map map ) throws ParserSymbolTableException{
if( resultMap == null || map == null || map.isEmpty() ){
return;
}
Iterator keyIterator = map.keySet().iterator();
Object key = null;
while( keyIterator.hasNext() ){
key = keyIterator.next();
if( !resultMap.containsKey( key ) ){
resultMap.put( key, map.get( key ) );
}
}
}
/**
* function isValidOverload
* @param origDecl
* @param newDecl
* @return boolean
*
* 3.3.7 "A class name or enumeration name can be hidden by the name of an
* object, function or enumerator declared in the same scope"
*
* 3.4-1 "Name lookup may associate more than one declaration with a name if
* it finds the name to be a function name"
*/
protected static boolean isValidOverload( ISymbol origSymbol, ISymbol newSymbol ){
TypeInfo.eType origType = origSymbol.getType();
TypeInfo.eType newType = newSymbol.getType();
//handle forward decls
if( origSymbol.getTypeInfo().isForwardDeclaration() ){
if( origSymbol.getTypeSymbol() == newSymbol )
return true;
//friend class declarations
if( origSymbol.getIsInvisible() && origSymbol.isType( newSymbol.getType() ) ){
origSymbol.getTypeInfo().setTypeSymbol( newSymbol );
return true;
}
}
if( (origType.compareTo(TypeInfo.t_class) >= 0 && origType.compareTo(TypeInfo.t_enumeration) <= 0) && //class name or enumeration ...
( newType == TypeInfo.t_type || (newType.compareTo( TypeInfo.t_function ) >= 0 /*&& newType <= TypeInfo.typeMask*/) ) ){
return true;
}
//if the origtype is not a class-name or enumeration name, then the only other
//allowable thing is if they are both functions.
if( origSymbol instanceof IParameterizedSymbol && newSymbol instanceof IParameterizedSymbol )
return isValidFunctionOverload( (IParameterizedSymbol) origSymbol, (IParameterizedSymbol) newSymbol );
else
return false;
}
protected static boolean isValidOverload( List origList, ISymbol newSymbol ){
if( origList.size() == 1 ){
return isValidOverload( (ISymbol)origList.iterator().next(), newSymbol );
} else if ( origList.size() > 1 ){
//the first thing can be a class-name or enumeration name, but the rest
//must be functions. So make sure the newDecl is a function before even
//considering the list
if( newSymbol.getType() != TypeInfo.t_function && newSymbol.getType() != TypeInfo.t_constructor ){
return false;
}
Iterator iter = origList.iterator();
ISymbol symbol = (ISymbol) iter.next();
boolean valid = isValidOverload( symbol, newSymbol );//( (symbol.getType().compareTo( TypeInfo.t_class ) >= 0 ) && (symbol.getType().compareTo( TypeInfo.t_enumeration ) <= 0 ) );
if( !valid && (symbol instanceof IParameterizedSymbol) )
valid = isValidFunctionOverload( (IParameterizedSymbol)symbol, (IParameterizedSymbol)newSymbol );
while( valid && iter.hasNext() ){
symbol = (ISymbol) iter.next();
valid = ( symbol instanceof IParameterizedSymbol) && isValidFunctionOverload( (IParameterizedSymbol)symbol, (IParameterizedSymbol)newSymbol );
}
return valid;
}
//empty list, return true
return true;
}
private static boolean isValidFunctionOverload( IParameterizedSymbol origSymbol, IParameterizedSymbol newSymbol ){
if( ( !origSymbol.isType( TypeInfo.t_function ) && !origSymbol.isType( TypeInfo.t_constructor ) ) ||
( ! newSymbol.isType( TypeInfo.t_function ) && ! newSymbol.isType( TypeInfo.t_constructor ) ) ){
return false;
}
//handle forward decls
if( origSymbol.getTypeInfo().isForwardDeclaration() &&
origSymbol.getTypeSymbol() == newSymbol )
{
return true;
}
if( origSymbol.hasSameParameters( newSymbol ) ){
//functions with the same name and same parameter types cannot be overloaded if any of them
//is static
if( origSymbol.getTypeInfo().checkBit( TypeInfo.isStatic ) || newSymbol.getTypeInfo().checkBit( TypeInfo.isStatic ) ){
return false;
}
//if none of them are static, then the function can be overloaded if they differ in the type
//of their implicit object parameter.
if( origSymbol.compareCVQualifiersTo( newSymbol ) != 0 ){
return true;
}
return false;
}
return true;
}
/**
*
* @param data
* @return Declaration
* @throws ParserSymbolTableException
*
* Resolve the foundItems set down to one declaration and return that
* declaration.
* If we successfully resolve, then the data.foundItems list will be
* cleared. If however, we were not able to completely resolve the set,
* then the data.foundItems set will be left with those items that
* survived the partial resolution and we will return null. (currently,
* this case applies to when we have overloaded functions and no parameter
* information)
*
* NOTE: data.parameters == null means there is no parameter information at
* all, when looking for functions with no parameters, an empty list must be
* provided in data.parameters.
*/
static protected ISymbol resolveAmbiguities( LookupData data ) throws ParserSymbolTableException{
ISymbol decl = null;
ISymbol obj = null;
IContainerSymbol cls = null;
if( data.foundItems == null || data.foundItems.isEmpty() || data.mode == LookupMode.PREFIX ){
return null;
}
int size = data.foundItems.size();
//Iterator iter = data.foundItems.iterator();
Object object = data.foundItems.get( data.name );
LinkedList functionList = new LinkedList();
if( object instanceof List ){
functionList.addAll( (List) object );
} else {
ISymbol symbol = (ISymbol) object;
if( symbol.isType( TypeInfo.t_function ) ){
functionList.add( symbol );
} else {
return symbol;
}
}
if( data.parameters == null ){
//we have no parameter information, if we only have one function, return
//that, otherwise we can't decide between them
if( functionList.size() == 1){
return (ISymbol) functionList.getFirst();
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_UnableToResolveFunction );
}
} else {
return resolveFunction( data, functionList );
}
}
static protected IParameterizedSymbol resolveFunction( LookupData data, List functions ) throws ParserSymbolTableException{
if( functions == null ){
return null;
}
reduceToViable( data, functions );
int numSourceParams = ( data.parameters == null ) ? 0 : data.parameters.size();
int numFns = functions.size();
if( numSourceParams == 0 ){
//no parameters
//if there is only 1 viable function, return it, if more than one, its ambiguous
if( numFns == 0 ){
return null;
} else if ( numFns == 1 ){
return (IParameterizedSymbol)functions.iterator().next();
} else if ( numFns == 2 ){
Iterator iter = functions.iterator();
while( iter.hasNext() ){
IParameterizedSymbol fn = (IParameterizedSymbol) iter.next();
if( fn.getTypeInfo().isForwardDeclaration() && fn.getTypeSymbol() != null ){
if( functions.contains( fn.getTypeSymbol() ) ){
return (IParameterizedSymbol) fn.getTypeSymbol();
}
}
}
}
if( data.parameters == null )
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
IParameterizedSymbol bestFn = null; //the best function
IParameterizedSymbol 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
Iterator iterFns = functions.iterator();
Iterator sourceParams = null;
Iterator targetParams = null;
int numTargetParams = 0;
int comparison;
Cost cost = null;
Cost temp = null;
TypeInfo source = null;
TypeInfo target = null;
boolean hasWorse = false;
boolean hasBetter = false;
boolean ambiguous = false;
boolean currHasAmbiguousParam = false;
boolean bestHasAmbiguousParam = false;
List parameters = null;
if( numSourceParams == 0 ){
parameters = new LinkedList();
parameters.add( new TypeInfo( TypeInfo.t_void, 0, null ) );
numSourceParams = 1;
} else {
parameters = data.parameters;
}
for( int i = numFns; i > 0; i-- ){
currFn = (IParameterizedSymbol) iterFns.next();
if( bestFn != null ){
if( bestFn.isForwardDeclaration() && bestFn.getTypeSymbol() == currFn ){
bestFn = currFn;
continue;
} else if( currFn.isForwardDeclaration() && currFn.getTypeSymbol() == bestFn ){
continue;
}
}
sourceParams = parameters.iterator();
List parameterList = null;
if( currFn.getParameterList().isEmpty() && !currFn.hasVariableArgs() ){
//the only way we get here and have no parameters, is if we are looking
//for a function that takes void parameters ie f( void )
parameterList = new LinkedList();
parameterList.add( currFn.getSymbolTable().newSymbol( "", TypeInfo.t_void ) );
} else {
parameterList = currFn.getParameterList();
}
targetParams = parameterList.iterator();
numTargetParams = parameterList.size();
if( currFnCost == null ){
currFnCost = new Cost [ numSourceParams ];
}
comparison = 0;
boolean varArgs = false;
for( int j = 0; j < numSourceParams; j++ ){
source = (TypeInfo) sourceParams.next();
if( targetParams.hasNext() )
target = ((ISymbol)targetParams.next()).getTypeInfo();
else
varArgs = true;
if( varArgs ){
cost = new Cost( source, null );
cost.rank = Cost.ELLIPSIS_CONVERSION;
} else if ( target.getHasDefault() && source.isType( TypeInfo.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 ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
}
return bestFn;
}
static private void reduceToViable( LookupData data, List functions ){
int numParameters = ( data.parameters == null ) ? 0 : data.parameters.size();
int num;
//Trim the list down to the set of viable functions
IParameterizedSymbol function;
Iterator iter = functions.iterator();
while( iter.hasNext() ){
function = (IParameterizedSymbol) iter.next();
num = ( function.getParameterList() == null ) ? 0 : function.getParameterList().size();
//if there are m arguments in the list, all candidate functions having m parameters
//are viable
if( num == numParameters ){
continue;
}
//check for void
else if( numParameters == 0 && num == 1 ){
ISymbol param = (ISymbol)function.getParameterList().iterator().next();
if( param.isType( TypeInfo.t_void ) )
continue;
}
else if( numParameters == 1 && num == 0 ){
TypeInfo paramType = (TypeInfo) data.parameters.iterator().next();
if( paramType.isType( TypeInfo.t_void ) )
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.hasVariableArgs() ) {
continue;
} else {
//not enough parameters, remove it
iter.remove();
}
}
//a candidate function having more than m parameters is viable only if the (m+1)-st
//parameter has a default argument
else {
ListIterator listIter = function.getParameterList().listIterator( num );
TypeInfo param;
for( int i = num; i > ( numParameters - num + 1); i-- ){
param = ((ISymbol)listIter.previous()).getTypeInfo();
if( !param.getHasDefault() ){
iter.remove();
break;
}
}
}
}
}
/**
* function ProcessDirectives
* @param Declaration decl
* @param LookupData data
* @param LinkedList directives
*
* Go through the directives and for each nominated namespace find the
* closest enclosing declaration for that namespace and decl, then add the
* nominated namespace to the lookup data for consideration when we reach
* the enclosing declaration.
*/
static private void processDirectives( IContainerSymbol symbol, LookupData data, List directives ){
IContainerSymbol enclosing = null;
IContainerSymbol temp = null;
int size = directives.size();
Iterator iter = directives.iterator();
for( int i = size; i > 0; i-- ){
temp = (IContainerSymbol) iter.next();
//namespaces are searched at most once
if( !data.visited.contains( temp ) ){
enclosing = getClosestEnclosingDeclaration( symbol, temp );
//the data.usingDirectives is a map from enclosing declaration to
//a list of namespaces to consider when we reach that enclosing
//declaration
LinkedList list = (data.usingDirectives == null )
? null
: (LinkedList) data.usingDirectives.get( enclosing );
if ( list == null ){
list = new LinkedList();
list.add( temp );
if( data.usingDirectives == null ){
data.usingDirectives = new HashMap();
}
data.usingDirectives.put( enclosing, list );
} else {
list.add( temp );
}
}
}
}
/**
* function getClosestEnclosingDeclaration
* @param decl1
* @param decl2
* @return Declaration
*
* 7.3.4-1 "During unqualified lookup, the names appear as if they were
* declared in the nearest enclosing namespace which contains both the
* using-directive and the nominated namespace"
*
* TBD: Consider rewriting this iteratively instead of recursively, for
* performance
*/
static private IContainerSymbol getClosestEnclosingDeclaration( ISymbol symbol1, ISymbol symbol2 ){
if( symbol1 == symbol2 ){
return ( symbol1 instanceof IContainerSymbol ) ? (IContainerSymbol) symbol1 : symbol1.getContainingSymbol();
}
if( symbol1.getDepth() == symbol2.getDepth() ){
return getClosestEnclosingDeclaration( symbol1.getContainingSymbol(), symbol2.getContainingSymbol() );
} else if( symbol1.getDepth() > symbol2.getDepth() ) {
return getClosestEnclosingDeclaration( symbol1.getContainingSymbol(), symbol2 );
} else {
return getClosestEnclosingDeclaration( symbol1, symbol2.getContainingSymbol() );
}
}
/**
*
* @param obj
* @param base
* @return int
* figure out if base is a base class of obj, and return the "distance" to
* the base class.
* ie:
* A -> B -> C
* the distance from A to B is 1 and from A to C is 2. This distance is used
* to rank standard pointer conversions.
*
* TBD: Consider rewriting iteratively for performance.
*/
static protected int hasBaseClass( ISymbol obj, ISymbol base ) throws ParserSymbolTableException {
return hasBaseClass( obj, base, false );
}
static private int hasBaseClass( ISymbol obj, ISymbol base, boolean throwIfNotVisible ) throws ParserSymbolTableException{
if( obj == base ){
return 0;
}
IDerivableContainerSymbol symbol = null;
TemplateInstance instance = null;
if( obj instanceof TemplateInstance ){
instance = (TemplateInstance) obj;
ISymbol temp = instance.getInstantiatedSymbol();
if( temp instanceof IDerivableContainerSymbol ){
symbol = (IDerivableContainerSymbol) temp;
} else {
return -1;
}
} else if( obj instanceof IDerivableContainerSymbol ){
symbol = (IDerivableContainerSymbol) obj;
} else {
return -1;
}
if( symbol.hasParents() ){
ISymbol temp = null;
IDerivableContainerSymbol parent = null;
IDerivableContainerSymbol.IParentSymbol wrapper;
Iterator iter = symbol.getParents().iterator();
int size = symbol.getParents().size();
for( int i = size; i > 0; i-- ){
wrapper = (IDerivableContainerSymbol.IParentSymbol) iter.next();
temp = wrapper.getParent();
boolean isVisible = ( wrapper.getVisibility() == ASTAccessVisibility.PUBLIC );
if( temp instanceof TemplateInstance ){
instance = (TemplateInstance) temp;
if( instance.getInstantiatedSymbol() instanceof IDerivableContainerSymbol ){
if( instance.getInstantiatedSymbol() == base ){
if( throwIfNotVisible && !isVisible )
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadVisibility );
else
return 1;
} else {
int n = hasBaseClass( instance, base, throwIfNotVisible );
if( n > 0 ){
return n + 1;
}
}
}
} else {
if( temp.isType( TypeInfo.t_undef ) && temp.getContainingSymbol().isType( TypeInfo.t_template ) ){
if( instance == null ) continue;
TypeInfo info = (TypeInfo) instance.getArgumentMap().get( temp );
if( info == null || !info.isType( TypeInfo.t_class, TypeInfo.t_struct ) ){
continue;
}
parent = (IDerivableContainerSymbol) info.getTypeSymbol();
}
else if ( temp instanceof IDerivableContainerSymbol ){
parent = (IDerivableContainerSymbol)temp;
} else {
continue;
}
if( parent == base ){
if( throwIfNotVisible && !isVisible )
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadVisibility );
else
return 1;
} else {
int n = hasBaseClass( parent, base, throwIfNotVisible );
if( n > 0 ){
return n + 1;
}
}
}
}
}
return -1;
}
static protected void getAssociatedScopes( ISymbol symbol, HashSet associated ){
if( symbol == null ){
return;
}
//if T is a class type, its associated classes are the class itself,
//and its direct and indirect base classes. its associated Namespaces are the
//namespaces in which its associated classes are defined
//if( symbol.getType() == TypeInfo.t_class ){
if( symbol instanceof IDerivableContainerSymbol ){
associated.add( symbol );
associated.add( symbol.getContainingSymbol() );
getBaseClassesAndContainingNamespaces( (IDerivableContainerSymbol) symbol, associated );
}
//if T is a union or enumeration type, its associated namespace is the namespace in
//which it is defined. if it is a class member, its associated class is the member's
//class
else if( symbol.getType() == TypeInfo.t_union || symbol.getType() == TypeInfo.t_enumeration ){
associated.add( symbol.getContainingSymbol() );
}
}
static private void getBaseClassesAndContainingNamespaces( IDerivableContainerSymbol obj, HashSet classes ){
if( obj.getParents() != null ){
if( classes == null ){
return;
}
Iterator iter = obj.getParents().iterator();
int size = obj.getParents().size();
IDerivableContainerSymbol.IParentSymbol wrapper;
ISymbol base;
for( int i = size; i > 0; i-- ){
wrapper = (IDerivableContainerSymbol.IParentSymbol) iter.next();
base = wrapper.getParent();
classes.add( base );
if( base.getContainingSymbol().getType() == TypeInfo.t_namespace ){
classes.add( base.getContainingSymbol());
}
getBaseClassesAndContainingNamespaces( (IDerivableContainerSymbol) base, classes );
}
}
}
static protected boolean okToAddUsingDeclaration( ISymbol obj, IContainerSymbol context ){
boolean okToAdd = false;
//7.3.3-5 A using-declaration shall not name a template-id
if( obj.isTemplateMember() && obj.getContainingSymbol().isType( TypeInfo.t_template ) ){
okToAdd = false;
}
//7.3.3-4
else if( context.isType( TypeInfo.t_class, TypeInfo.t_struct ) ){
IContainerSymbol container = obj.getContainingSymbol();
try{
//a member of a base class
if( obj.getContainingSymbol().getType() == context.getType() ){
okToAdd = ( hasBaseClass( (IDerivableContainerSymbol) context, (IDerivableContainerSymbol) container ) > 0 );
}
else if ( obj.getContainingSymbol().getType() == TypeInfo.t_union ) {
// TODO : must be an _anonymous_ union
container = container.getContainingSymbol();
okToAdd = ( container instanceof IDerivableContainerSymbol )
? ( hasBaseClass( (IDerivableContainerSymbol)context, (IDerivableContainerSymbol) container ) > 0 )
: false;
}
//an enumerator for an enumeration
else if ( obj.getType() == TypeInfo.t_enumerator ){
container = container.getContainingSymbol();
okToAdd = ( container instanceof IDerivableContainerSymbol )
? ( hasBaseClass( (IDerivableContainerSymbol)context, (IDerivableContainerSymbol) container ) > 0 )
: false;
}
} catch ( ParserSymbolTableException e ) {
//not going to happen since we didn't ask for the visibility exception from hasBaseClass
}
} else {
okToAdd = true;
}
return okToAdd;
}
static private Cost lvalue_to_rvalue( TypeInfo source, TypeInfo target ){
//lvalues will have type t_type
if( source.isType( TypeInfo.t_type ) ){
source = getFlatTypeInfo( source );
}
if( target.isType( TypeInfo.t_type ) ){
ISymbol symbol = target.getTypeSymbol();
if( symbol != null && symbol.isForwardDeclaration() && symbol.getTypeSymbol() != null ){
target = new TypeInfo( target );
target.setType( TypeInfo.t_type );
target.setTypeSymbol( symbol.getTypeSymbol() );
}
}
Cost cost = new Cost( source, target );
//if either source or target is null here, then there was a problem
//with the parameters and we can't match them.
if( cost.source == null || cost.target == null ){
return cost;
}
TypeInfo.PtrOp op = null;
if( cost.source.hasPtrOperators() ){
List sourcePtrs = cost.source.getPtrOperators();
Iterator iterator = sourcePtrs.iterator();
TypeInfo.PtrOp ptr = (TypeInfo.PtrOp)iterator.next();
if( ptr.getType() == TypeInfo.PtrOp.t_reference ){
iterator.remove();
}
int size = sourcePtrs.size();
Iterator iter = sourcePtrs.iterator();
for( int i = size; i > 0; i-- ){
op = (TypeInfo.PtrOp) iter.next();
if( op.getType() == TypeInfo.PtrOp.t_array ){
op.setType( TypeInfo.PtrOp.t_pointer );
}
}
}
if( cost.target.hasPtrOperators() ){
List targetPtrs = cost.target.getPtrOperators();
ListIterator iterator = targetPtrs.listIterator();
TypeInfo.PtrOp ptr = (TypeInfo.PtrOp)iterator.next();
if( ptr.getType() == TypeInfo.PtrOp.t_reference ){
if( ptr.isConst() || ptr.isVolatile() ){
iterator.set( new PtrOp( PtrOp.t_undef, ptr.isConst(), ptr.isVolatile() ) );
} else {
iterator.remove();
}
cost.targetHadReference = true;
}
int size = targetPtrs.size();
Iterator iter = targetPtrs.iterator();
for( int i = size; i > 0; i-- ){
op = (TypeInfo.PtrOp) iter.next();
if( op.getType() == TypeInfo.PtrOp.t_array ){
op.setType( TypeInfo.PtrOp.t_pointer );
}
}
}
return cost;
}
/**
* qualificationConversion
* @param cost
*
* see spec section 4.4 regarding qualification conversions
*/
static private void qualificationConversion( Cost cost ){
int size = cost.source.getPtrOperators().size();
int size2 = cost.target.getPtrOperators().size();
TypeInfo.PtrOp op1 = null, op2 = null;
boolean canConvert = true;
Iterator iter1 = cost.source.getPtrOperators().iterator();
Iterator iter2 = cost.target.getPtrOperators().iterator();
if( size != size2 ){
if( size2 - size == 1 ){
op2 = (PtrOp) iter2.next();
if( op2.isConst() || op2.isVolatile() ){
canConvert = true;
} else {
canConvert = false;
}
} else {
canConvert = false;
}
} else if ( size == 1 ){
op1 = (TypeInfo.PtrOp) iter1.next();
op2 = (TypeInfo.PtrOp) iter2.next();
//can only convert if op2 is more qualified
if( ( op1.isConst() && !op2.isConst() ) ||
( op1.isVolatile() && !op2.isVolatile() ) )
{
cost.qualification = 0;
return;
}
canConvert = true;
} else if( size > 0 ){
op1 = (TypeInfo.PtrOp) iter1.next();
op2 = (TypeInfo.PtrOp) iter2.next();
boolean constInEveryCV2k = true;
for( int j= 1; j < size; j++ ){
op1 = (TypeInfo.PtrOp) iter1.next();
op2 = (TypeInfo.PtrOp) iter2.next();
//pointer types must be similar
if( op1.getType() != op2.getType() ){
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<k<j
if( ( op1.compareCVTo( op2 ) != 0 ) && !constInEveryCV2k ){
canConvert = false;
break;
}
constInEveryCV2k &= op2.isConst();
}
}
if( canConvert == true ){
cost.qualification = 1;
cost.rank = Cost.LVALUE_OR_QUALIFICATION_RANK;
} else {
cost.qualification = 0;
}
}
/**
*
* @param source
* @param target
* @return int
*
* 4.5-1 char, signed char, unsigned char, short int or unsigned short int
* can be converted to int if int can represent all the values of the source
* type, otherwise they can be converted to unsigned int.
* 4.5-2 wchar_t or an enumeration can be converted to the first of the
* following that can hold it: int, unsigned int, long unsigned long.
* 4.5-4 bool can be promoted to int
* 4.6 float can be promoted to double
*/
static private void promotion( Cost cost ){
TypeInfo src = cost.source;
TypeInfo trg = cost.target;
int mask = TypeInfo.isShort | TypeInfo.isLong | TypeInfo.isUnsigned;
if( (src.isType( TypeInfo.t_bool, TypeInfo.t_float ) || src.isType( TypeInfo.t_enumeration )) &&
(trg.isType( TypeInfo.t_int ) || trg.isType( TypeInfo.t_double )) )
{
if( src.getType() == trg.getType() && (( src.getTypeInfo() & mask) == (trg.getTypeInfo() & mask)) ){
//same, no promotion needed
return;
}
if( src.isType( TypeInfo.t_float ) ){
cost.promotion = trg.isType( TypeInfo.t_double ) ? 1 : 0;
} else {
cost.promotion = ( trg.isType( TypeInfo.t_int ) && trg.canHold( src ) ) ? 1 : 0;
}
} else {
cost.promotion = 0;
}
cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK;
}
/**
*
* @param source
* @param target
* @return int
*
*/
static private void conversion( Cost cost ){
TypeInfo src = cost.source;
TypeInfo trg = cost.target;
int temp = -1;
cost.conversion = 0;
cost.detail = 0;
if( !src.hasSamePtrs( trg ) ){
return;
}
if( src.hasPtrOperators() && src.getPtrOperators().size() == 1 ){
TypeInfo.PtrOp ptr = (TypeInfo.PtrOp)src.getPtrOperators().iterator().next();
ISymbol srcDecl = src.isType( TypeInfo.t_type ) ? src.getTypeSymbol() : null;
ISymbol trgDecl = trg.isType( TypeInfo.t_type ) ? trg.getTypeSymbol() : null;
if( ptr.getType() == TypeInfo.PtrOp.t_pointer ){
if( srcDecl == null || (trgDecl == null && !trg.isType( TypeInfo.t_void )) ){
return;
}
//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( trg.isType( TypeInfo.t_void ) ){
cost.rank = Cost.CONVERSION_RANK;
cost.conversion = 1;
cost.detail = 2;
return;
}
cost.detail = 1;
//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.
if( (srcDecl instanceof IDerivableContainerSymbol) && trgDecl.isType( srcDecl.getType() ) ){
try {
temp = hasBaseClass( (IDerivableContainerSymbol) srcDecl, (IDerivableContainerSymbol) trgDecl );
} 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.conversion = ( temp > -1 ) ? temp : 0;
cost.detail = 1;
return;
}
} else if( ptr.getType() == TypeInfo.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
if( srcDecl == null || trgDecl == null ){
return;
}
TypeInfo.PtrOp srcPtr = trg.hasPtrOperators() ? (TypeInfo.PtrOp)trg.getPtrOperators().iterator().next() : null;
if( trgDecl.isType( srcDecl.getType() ) && srcPtr != null && srcPtr.getType() == TypeInfo.PtrOp.t_memberPointer ){
try {
temp = hasBaseClass( (IDerivableContainerSymbol)ptr.getMemberOf(), (IDerivableContainerSymbol)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;
}
}
} else if( !src.hasPtrOperators() ) {
//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.
if( src.isType( TypeInfo.t_bool, TypeInfo.t_int ) ||
src.isType( TypeInfo.t_float, TypeInfo.t_double ) ||
src.isType( TypeInfo.t_enumeration ) )
{
if( trg.isType( TypeInfo.t_bool, TypeInfo.t_int ) ||
trg.isType( TypeInfo.t_float, TypeInfo.t_double ) )
{
cost.rank = Cost.CONVERSION_RANK;
cost.conversion = 1;
}
}
}
}
static private void derivedToBaseConversion( Cost cost ) throws ParserSymbolTableException{
TypeInfo src = cost.source;
TypeInfo trg = cost.target;
ISymbol srcDecl = src.isType( TypeInfo.t_type ) ? src.getTypeSymbol() : null;
ISymbol trgDecl = trg.isType( TypeInfo.t_type ) ? trg.getTypeSymbol() : null;
if( !src.hasSamePtrs( trg ) || srcDecl == null || trgDecl == null || !cost.targetHadReference ){
return;
}
int temp = hasBaseClass( (IDerivableContainerSymbol) srcDecl, (IDerivableContainerSymbol) trgDecl, true );
if( temp > -1 ){
cost.rank = Cost.DERIVED_TO_BASE_CONVERSION;
cost.conversion = temp;
}
}
static private Cost checkStandardConversionSequence( TypeInfo source, TypeInfo target ) throws ParserSymbolTableException{
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?
if( cost.source.isType( TypeInfo.t_type ) && cost.target.isType( TypeInfo.t_type ) ){
if( cost.target.hasSamePtrs( cost.source ) ){
ISymbol srcSymbol = cost.source.getTypeSymbol();
ISymbol trgSymbol = cost.target.getTypeSymbol();
if( srcSymbol != null && trgSymbol != null ){
if( srcSymbol.equals( trgSymbol ) )
{
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( TypeInfo source, TypeInfo target ) throws ParserSymbolTableException {
Cost cost = null;
Cost constructorCost = null;
Cost conversionCost = null;
ISymbol targetDecl = null;
ISymbol sourceDecl = null;
IParameterizedSymbol constructor = null;
IParameterizedSymbol conversion = null;
//constructors
if( target.getType() == TypeInfo.t_type ){
targetDecl = target.getTypeSymbol();
if( targetDecl.isType( TypeInfo.t_class, TypeInfo.t_union ) ){
LookupData data = new LookupData( EMPTY_NAME, TypeInfo.t_constructor, null );
data.parameters = new LinkedList();
data.parameters.add( source );
data.forUserDefinedConversion = true;
IDerivableContainerSymbol container = (IDerivableContainerSymbol) targetDecl;
if( targetDecl instanceof TemplateInstance ){
data.templateInstance = targetDecl;
container = (IDerivableContainerSymbol)((TemplateInstance) targetDecl).getInstantiatedSymbol();
}
if( !container.getConstructors().isEmpty() ){
LinkedList constructors = new LinkedList( container.getConstructors() );
constructor = resolveFunction( data, constructors );
}
if( constructor != null && constructor.getTypeInfo().checkBit( TypeInfo.isExplicit ) ){
constructor = null;
}
}
}
//conversion operators
if( source.getType() == TypeInfo.t_type ){
source = getFlatTypeInfo( source );
sourceDecl = ( source != null ) ? source.getTypeSymbol() : null;
if( sourceDecl != null && (sourceDecl instanceof IContainerSymbol) ){
String name = target.toString();
if( !name.equals(EMPTY_NAME) ){
LookupData data = new LookupData( "operator " + name, TypeInfo.t_function, null ); //$NON-NLS-1$
LinkedList params = new LinkedList();
data.parameters = params;
data.forUserDefinedConversion = true;
data.foundItems = lookupInContained( data, (IContainerSymbol) sourceDecl );
conversion = (IParameterizedSymbol)resolveAmbiguities( data );
}
}
}
if( constructor != null ){
constructorCost = checkStandardConversionSequence( (TypeInfo) new TypeInfo( TypeInfo.t_type, 0, constructor.getContainingSymbol() ), target );
}
if( conversion != null ){
conversionCost = checkStandardConversionSequence( (TypeInfo) new TypeInfo( target.getType(), 0, target.getTypeSymbol() ), 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;
}
/**
* Determine the type of a conditional operator based on the second and third operands
* @param secondOp
* @param thirdOp
* @return
* Spec 5.16
* Determine if the second operand can be converted to match the third operand, and vice versa.
* - If both can be converted, or one can be converted but the conversion is ambiguous, the program
* is illformed (throw ParserSymbolTableException)
* - If neither can be converted, further checking must be done (return null)
* - If exactly one conversion is possible, that conversion is applied ( return the other TypeInfo )
*/
static public TypeInfo getConditionalOperand( TypeInfo secondOp, TypeInfo thirdOp ) throws ParserSymbolTableException{
//can secondOp convert to thirdOp ?
Cost secondCost = checkStandardConversionSequence( secondOp, getFlatTypeInfo( thirdOp ) );
if( secondCost.rank == Cost.NO_MATCH_RANK ){
secondCost = checkUserDefinedConversionSequence( secondOp, getFlatTypeInfo( thirdOp ) );
}
Cost thirdCost = checkStandardConversionSequence( thirdOp, getFlatTypeInfo( secondOp ) );
if( thirdCost.rank == Cost.NO_MATCH_RANK ){
thirdCost = checkUserDefinedConversionSequence( thirdOp, getFlatTypeInfo( secondOp ) );
}
boolean canConvertSecond = ( secondCost != null && secondCost.rank != Cost.NO_MATCH_RANK );
boolean canConvertThird = ( thirdCost != null && thirdCost.rank != Cost.NO_MATCH_RANK );
if( !canConvertSecond && !canConvertThird ){
//neither can be converted
return null;
} else if ( canConvertSecond && canConvertThird ){
//both can be converted -> illformed
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
} else {
if( canConvertSecond ){
if( secondCost.userDefined == Cost.AMBIGUOUS_USERDEFINED_CONVERSION ){
//conversion is ambiguous -> ill-formed
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
} else {
return thirdOp;
}
} else {
if( thirdCost.userDefined == Cost.AMBIGUOUS_USERDEFINED_CONVERSION ){
//conversion is ambiguous -> ill-formed
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
} else {
return secondOp;
}
}
}
}
/**
*
* @param decl
* @return TypeInfo
* The top level TypeInfo represents modifications to the object and the
* remaining TypeInfo's represent the object.
*/
// TODO move this to ITypeInfo ?
static protected TypeInfo getFlatTypeInfo( TypeInfo topInfo ){
TypeInfo returnInfo = topInfo;
TypeInfo info = null;
if( topInfo.getType() == TypeInfo.t_type && topInfo.getTypeSymbol() != null ){
returnInfo = (TypeInfo)new TypeInfo();
ISymbol typeSymbol = topInfo.getTypeSymbol();
info = typeSymbol.getTypeInfo();
while( info.getTypeSymbol() != null && ( info.getType() == TypeInfo.t_type || info.isForwardDeclaration() ) ){
typeSymbol = info.getTypeSymbol();
returnInfo.addPtrOperator( info.getPtrOperators() );
info = typeSymbol.getTypeInfo();
}
if( info.isType( TypeInfo.t_class, TypeInfo.t_enumeration ) ){
returnInfo.setType( TypeInfo.t_type );
returnInfo.setTypeSymbol( typeSymbol );
} else {
returnInfo.setTypeInfo( info.getTypeInfo() );
returnInfo.setType( info.getType() );
returnInfo.setTypeSymbol( null );
returnInfo.addPtrOperator( info.getPtrOperators() );
}
returnInfo.applyOperatorExpressions( topInfo.getOperatorExpressions() );
if( topInfo.hasPtrOperators() ){
TypeInfo.PtrOp topPtr = (PtrOp) topInfo.getPtrOperators().iterator().next();
TypeInfo.PtrOp ptr = null;
if( returnInfo.hasPtrOperators() ){
ptr = (PtrOp)returnInfo.getPtrOperators().iterator().next();
} else {
ptr = new PtrOp();
returnInfo.addPtrOperator( ptr );
ptr.setType( topPtr.getType() );
}
ptr.setConst( topPtr.isConst() );
ptr.setVolatile( topPtr.isVolatile() );
}
} else {
returnInfo = new TypeInfo( topInfo );
}
return returnInfo;
}
static private IParameterizedSymbol matchTemplatePartialSpecialization( IParameterizedSymbol template, List args ){
if( template == null ){
return null;
}
List specs = template.getSpecializations();
int size = ( specs != null ) ? specs.size() : 0;
if( size == 0 ){
return template;
}
IParameterizedSymbol bestMatch = null;
boolean bestMatchIsBest = true;
Iterator iter = specs.iterator();
IParameterizedSymbol spec = null;
List specArgs = null;
for( int i = size; i > 0; i-- ){
spec = (IParameterizedSymbol) iter.next();
specArgs = spec.getArgumentList();
if( specArgs == null || specArgs.size() != args.size() ){
continue;
}
ISymbol sym1 = null, sym2 = null;
Iterator iter1 = specArgs.iterator();
Iterator iter2 = args.iterator();
HashMap map = new HashMap();
//String name = null;
boolean match = true;
for( int j = specArgs.size(); j > 0; j-- ){
sym1 = (ISymbol)iter1.next();
TypeInfo info2 = (TypeInfo) iter2.next();
if( info2.isType( TypeInfo.t_type ) ){
sym2 = sym2.getTypeSymbol();
} else {
sym2 = template.getSymbolTable().newSymbol( EMPTY_NAME );
sym2.setTypeInfo( info2 );
}
if( !deduceTemplateArgument( map, sym1, sym2, null ) ){
match = false;
break;
}
/*
name = sym1.getName();
if( name.equals( "" ) ){
//no name, only type
} else if( map.containsKey( name ) ) {
ISymbol val = (ISymbol) map.get( name );
if( val.getType() != sym2.getType() ){
match = false;
break;
}
} else {
map.put( name, sym2 );
}
*/
}
if( match ){
int compare = orderSpecializations( bestMatch, spec );
if( compare == 0 ){
bestMatchIsBest = false;
} else if( compare < 0 ) {
bestMatch = spec;
bestMatchIsBest = true;
}
}
}
return bestMatchIsBest ? bestMatch : null;
}
/**
* Compare spec1 to spec2. Return > 0 if spec1 is more specialized, < 0 if spec2
* is more specialized, = 0 otherwise.
* @param spec1
* @param spec2
* @return
*/
static private int orderSpecializations( IParameterizedSymbol spec1, IParameterizedSymbol spec2 ){
if( spec1 == null ){
return -1;
}
Iterator iter = spec1.getContainedSymbols().keySet().iterator();
ISymbol decl = (ISymbol) spec1.getContainedSymbols().get( iter.next() );
//to order class template specializations, we need to transform them into function templates
if( decl.isType( TypeInfo.t_class ) ) {
spec1 = classTemplateSpecializationToFunctionTemplate( spec1 );
spec2 = classTemplateSpecializationToFunctionTemplate( spec2 );
}
TemplateInstance transformed1 = transformFunctionTemplateForOrdering( spec1 );
TemplateInstance transformed2 = transformFunctionTemplateForOrdering( spec2 );
//Using the transformed parameter list, perform argument deduction against the other
//function template
boolean d1 = deduceTemplateArguments( spec2, transformed1 );
boolean d2 = deduceTemplateArguments( spec1, transformed2 );
//The transformed template is at least as specialized as the other iff the deduction
//succeeds and the deduced parameter types are an exact match
//A template is more specialized than another iff it is at least as specialized as the
//other template and that template is not at least as specialized as the first.
if( d1 && d2 || !d1 && !d2 )
return 0;
else if( d1 && !d2 )
return 1;
else
return -1;
}
/**
*
* @param template
* @param args
* @return
*
* A type that is specified in terms of template parameters (P) is compared with an actual
* type (A), and an attempt is made to find template argument vaules that will make P,
* after substitution of the deduced values, compatible with A.
*/
static private boolean deduceTemplateArguments( IParameterizedSymbol template, TemplateInstance argSource ){
if( template.getContainedSymbols() == null || template.getContainedSymbols().size() != 1 ){
return false;
}
Iterator iter = template.getContainedSymbols().keySet().iterator();
ISymbol templateSymbol = (ISymbol) template.getContainedSymbols().get( iter.next() );
if( !templateSymbol.isType( TypeInfo.t_function ) ){
return false;
}
IParameterizedSymbol argTemplate = (IParameterizedSymbol)argSource.getInstantiatedSymbol();
iter = argTemplate.getContainedSymbols().keySet().iterator();
ISymbol argFunction = (ISymbol) argTemplate.getContainedSymbols().get( iter.next() );
if( !argFunction.isType( TypeInfo.t_function ) ){
return false;
}
List args = ((IParameterizedSymbol) argFunction).getParameterList();
IParameterizedSymbol function = (IParameterizedSymbol) templateSymbol;
if( function.getParameterList() == null || function.getParameterList().size() != args.size() ){
return false;
}
HashMap map = new HashMap();
Iterator pIter = function.getParameterList().iterator();
Iterator aIter = args.iterator();
while( pIter.hasNext() ){
if( !deduceTemplateArgument( map, (ISymbol) pIter.next(), (ISymbol) aIter.next(), argSource.getArgumentMap() ) ){
return false;
}
}
return true;
}
static private boolean deduceTemplateArgument( Map map, ISymbol p, ISymbol a, Map argumentMap ){
if( argumentMap != null && argumentMap.containsKey( a ) ){
a = (ISymbol) argumentMap.get( a );
}
ISymbol pSymbol = p, aSymbol = a;
if( p.isType( TypeInfo.t_type ) ){
pSymbol = p.getTypeSymbol();
aSymbol = a.isType( TypeInfo.t_type ) ? a.getTypeSymbol() : a;
return deduceTemplateArgument( map, pSymbol, aSymbol, argumentMap );
} else {
if( pSymbol.isTemplateMember() && pSymbol.isType( TypeInfo.t_undef ) ){
//T* or T& or T[ const ]
//also
List pPtrs = pSymbol.getPtrOperators();
List aPtrs = aSymbol.getPtrOperators();
if( pPtrs != null ){
TypeInfo.PtrOp pOp = (TypeInfo.PtrOp) pPtrs.iterator().next();;
TypeInfo.PtrOp aOp = ( aPtrs != null ) ? (TypeInfo.PtrOp)pPtrs.iterator().next() : null;
if( pOp != null && aOp != null && pOp.getType() == aOp.getType() ){
if( pOp.getType() == TypeInfo.PtrOp.t_memberPointer ){
} else {
TypeInfo type = new TypeInfo( aSymbol.getTypeInfo() );
type.getPtrOperators().clear();
map.put( pSymbol.getName(), type );
return true;
}
} else {
return false;
}
} else {
//T
map.put( pSymbol.getName(), a.getTypeInfo() );
return true;
}
}
//template-name<T> or template-name<i>
else if( pSymbol.isType( TypeInfo.t_template ) && aSymbol.isType( TypeInfo.t_template ) ){
List pArgs = ((IParameterizedSymbol)pSymbol).getArgumentList();
List aArgs = ((IParameterizedSymbol)aSymbol).getArgumentList();
if( pArgs == null || aArgs == null || pArgs.size() != aArgs.size()){
return false;
}
Iterator pIter = pArgs.iterator();
Iterator aIter = aArgs.iterator();
while( pIter.hasNext() ){
if( !deduceTemplateArgument( map, (ISymbol) pIter.next(), (ISymbol) aIter.next(), argumentMap ) ){
return false;
}
}
}
//T (*) ( ), T ( T::* ) ( T ), & variations
else if( pSymbol.isType( TypeInfo.t_function ) && aSymbol.isType( TypeInfo.t_function ) ){
IParameterizedSymbol pFunction = (IParameterizedSymbol)pSymbol;
IParameterizedSymbol aFunction = (IParameterizedSymbol)aSymbol;
if( !deduceTemplateArgument( map, aFunction.getReturnType(), pFunction.getReturnType(), argumentMap ) ){
return false;
}
if( pSymbol.getPtrOperators() != null ){
List ptrs = pSymbol.getPtrOperators();
TypeInfo.PtrOp op = (TypeInfo.PtrOp) ptrs.iterator().next();;
if( op.getType() == TypeInfo.PtrOp.t_memberPointer ){
if( !deduceTemplateArgument( map, op.getMemberOf(), pFunction.getContainingSymbol(), argumentMap ) ){
return false;
}
}
}
List pParams = pFunction.getParameterList();
List aParams = aFunction.getParameterList();
if( pParams.size() != aParams.size() ){
return false;
} else {
Iterator pIter = pParams.iterator();
Iterator aIter = aParams.iterator();
while( pIter.hasNext() ){
if( !deduceTemplateArgument( map, (ISymbol) pIter.next(), (ISymbol) aIter.next(), argumentMap ) ){
return false;
}
}
}
} else if( pSymbol.getType() == aSymbol.getType() ){
if( pSymbol.getTypeInfo().getHasDefault() ){
if( !aSymbol.getTypeInfo().getHasDefault() ||
aSymbol.getTypeInfo().getDefault().equals( pSymbol.getTypeInfo().getDefault() ) )
{
return false;
}
}
//value
map.put( pSymbol.getName(), aSymbol.getTypeInfo() );
return true;
}
}
return false;
}
/**
* transform the class template to a function template as described in the spec
* 14.5.4.2-1
* @param template
* @return IParameterizedSymbol
* the function template has the same template parameters as the partial specialization and
* has a single function parameter whose type is a class template specialization with the template
* arguments of the partial specialization
*/
static private IParameterizedSymbol classTemplateSpecializationToFunctionTemplate( IParameterizedSymbol template ){
IParameterizedSymbol transformed = (IParameterizedSymbol) template.clone();
transformed.getArgumentList().clear();
transformed.getContainedSymbols().clear();
IParameterizedSymbol function = template.getSymbolTable().newParameterizedSymbol( transformed.getName(), TypeInfo.t_function );
try{
transformed.addSymbol( function );
} catch ( ParserSymbolTableException e ){
//we shouldn't get this because there aren't any other symbols in the template
}
function.addParameter( template );
return transformed;
}
/**
* transform a function template for use in partial ordering, as described in the
* spec 14.5.5.2-3
* @param template
* @return
* -for each type template parameter, synthesize a unique type and substitute that for each
* occurence of that parameter in the function parameter list
* -for each non-type template parameter, synthesize a unique value of the appropriate type and
* susbstitute that for each occurence of that parameter in the function parameter list
* for each template template parameter, synthesize a unique class template and substitute that
* for each occurence of that parameter in the function parameter list
*/
static private TemplateInstance transformFunctionTemplateForOrdering( IParameterizedSymbol template ){
List paramList = template.getParameterList();
int size = ( paramList != null ) ? paramList.size() : 0;
if( size == 0 ){
return null;
}
HashMap map = new HashMap();
for( Iterator iterator = paramList.iterator(); iterator.hasNext(); ) {
ISymbol param = (ISymbol) iterator.next();
ISymbol val = template.getSymbolTable().newSymbol( EMPTY_NAME, TypeInfo.t_type );
if( false /* is value */ ){
//val.getTypeInfo().setHasDefault()
}
map.put( param, val );
}
return new TemplateInstance( template.getSymbolTable(), template, map );
}
//private Stack _contextStack = new Stack();
private IContainerSymbol _compilationUnit;
private ParserLanguage _language;
private LinkedList undoList = new LinkedList();
private HashSet markSet = new HashSet();
public void setLanguage( ParserLanguage language ){
_language = language;
}
public ParserLanguage getLanguage(){
return _language;
}
protected void pushCommand( Command command ){
undoList.addFirst( command );
}
public Mark setMark(){
Mark mark = new Mark();
undoList.addFirst( mark );
markSet.add( mark );
return mark;
}
public boolean rollBack( Mark toMark ){
if( markSet.contains( toMark ) ){
markSet.remove( toMark );
Command command = ( Command )undoList.removeFirst();
while( command != toMark ){
command.undoIt();
command = ( Command ) undoList.removeFirst();
}
return true;
}
return false;
}
public boolean commit( Mark toMark ){
if( markSet.contains( toMark ) ){
markSet.remove( toMark );
Command command = ( Command )undoList.removeLast();
while( command != toMark ){
command = (Command) undoList.removeLast();
}
return true;
}
return false;
}
static abstract protected class Command{
abstract public void undoIt();
}
static public class Mark extends Command{
public void undoIt(){ };
}
static public class LookupMode extends Enum{
public static final LookupMode PREFIX = new LookupMode( 1 );
public static final LookupMode NORMAL = new LookupMode( 2 );
private LookupMode( int constant)
{
super( constant );
}
}
static protected class LookupData
{
public Set ambiguities;
public String name;
public Map usingDirectives;
public Set visited = new HashSet(); //used to ensure we don't visit things more than once
public HashSet inheritanceChain; //used to detect circular inheritance
public List parameters; //parameter info for resolving functions
public HashSet associated; //associated namespaces for argument dependant lookup
public ISymbol stopAt; //stop looking along the stack once we hit this declaration
public TypeFilter filter = null;
public boolean qualified = false;
public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false;
public boolean forUserDefinedConversion = false;
public Map foundItems = null;
public ISymbol templateInstance = null;
public LookupMode mode = LookupMode.NORMAL;
public LookupData( String n, TypeInfo.eType t, ISymbol i ){
name = n;
filter = new TypeFilter( t );
templateInstance = i;
}
public LookupData( String n, TypeFilter f, ISymbol i ){
name = n;
filter = ( f != null ) ? f : new TypeFilter( TypeInfo.t_any );
templateInstance = i;
}
}
static private class Cost
{
public Cost( TypeInfo s, TypeInfo t ){
source = ( s != null ) ? new TypeInfo( s ) : new TypeInfo();
target = ( t != null ) ? new TypeInfo( t ) : new TypeInfo();
}
public TypeInfo source;
public TypeInfo 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;
} else {
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 {
int size = cost.target.hasPtrOperators() ? cost.target.getPtrOperators().size() : 0;
int size2 = target.hasPtrOperators() ? target.getPtrOperators().size() : 0;
ListIterator iter1 = cost.target.getPtrOperators().listIterator( size );
ListIterator iter2 = target.getPtrOperators().listIterator( size2 );
TypeInfo.PtrOp op1 = null, op2 = null;
int subOrSuper = 0;
for( int i = ( size < size2 ) ? size : size2; i > 0; i-- ){
op1 = (TypeInfo.PtrOp)iter1.previous();
op2 = (TypeInfo.PtrOp)iter2.previous();
if( subOrSuper == 0)
subOrSuper = op1.compareCVTo( op2 );
else if( ( subOrSuper > 0 && ( op1.compareCVTo( op2 ) < 0 )) ||
( subOrSuper < 0 && ( op1.compareCVTo( op2 ) > 0 )) )
{
result = -1;
break;
}
}
if( result == -1 ){
result = 0;
} else {
if( size == size2 ){
result = subOrSuper;
} else {
result = size - size2;
}
}
}
}
return result;
}
}
/**
* The visibility of the symbol is modified by the visibility of the base classes
* @param symbol
* @param qualifyingSymbol
* @return
*/
public static ASTAccessVisibility getVisibility(ISymbol symbol, IContainerSymbol qualifyingSymbol) throws ParserSymbolTableException {
IContainerSymbol container = symbol.getContainingSymbol();
if( qualifyingSymbol == null || container.equals( qualifyingSymbol ) ){
ISymbolASTExtension extension = symbol.getASTExtension();
IASTNode node = extension != null ? extension.getPrimaryDeclaration() : null;
if( node != null && node instanceof IASTMember ){
return ((IASTMember)node).getVisiblity();
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_InternalError );
}
}
if( ! (qualifyingSymbol instanceof IDerivableContainerSymbol) ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_InternalError );
}
List parents = ((IDerivableContainerSymbol) qualifyingSymbol).getParents();
Iterator iter = parents.iterator();
IParentSymbol parent = null;
ASTAccessVisibility symbolAccess = null;
ASTAccessVisibility parentAccess = null;
while( iter.hasNext() ){
parent = (IParentSymbol) iter.next();
if( container == parent.getParent() ){
parentAccess = parent.getAccess();
symbolAccess = ((IASTMember)symbol.getASTExtension().getPrimaryDeclaration()).getVisiblity();
return ( parentAccess.getEnumValue() > symbolAccess.getEnumValue() ) ? parentAccess : symbolAccess;
}
}
iter = parents.iterator();
//if static or an enumerator, the symbol could be visible through more than one path through the heirarchy,
//so we need to check all paths
boolean checkAllPaths = ( symbol.isType( TypeInfo.t_enumerator ) || symbol.getTypeInfo().checkBit( TypeInfo.isStatic ) );
ASTAccessVisibility resultingAccess = null;
while( iter.hasNext() ){
parent = (IParentSymbol) iter.next();
parentAccess = parent.getAccess();
symbolAccess = getVisibility( symbol, (IContainerSymbol) parent.getParent() );
if( symbolAccess != null ){
symbolAccess = ( parentAccess.getEnumValue() > symbolAccess.getEnumValue() ) ? parentAccess : symbolAccess;
if( checkAllPaths ){
if( resultingAccess != null )
resultingAccess = ( resultingAccess.getEnumValue() > symbolAccess.getEnumValue() ) ? symbolAccess : resultingAccess;
else
resultingAccess = symbolAccess;
} else {
return symbolAccess;
}
}
}
return resultingAccess;
}
}