Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-patch] ParserSymbolTable NPE fixes

This is my previous patch updated with a test and resubmitted.

It fixes some NPE's in function resolution if the parameter information is 
bad. 
It also tries to clarify conversion sequence ranking with comments and 
constants.

-Andrew

Index: parser/ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/parser/ChangeLog,v
retrieving revision 1.121
diff -u -r1.121 ChangeLog
--- parser/ChangeLog	11 Sep 2003 18:05:55 -0000	1.121
+++ parser/ChangeLog	12 Sep 2003 14:04:54 -0000
@@ -1,3 +1,7 @@
+2003-09-12 Andrew Niefer
+	Fixed some NPEs in ParserSymbolTable.getFlatTypeInfo
+	Added some comments and created some constants to help clarify ranking of conversion sequences
+
 2003-09-11 John Camelon
 	Fixed Bug 42840 : Search: Cannot find things after double declarations 
 	Fixed Bug 42798 : Selected #include <Angled> off by 1 char 
Index: parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java,v
retrieving revision 1.18
diff -u -r1.18 ParserSymbolTable.java
--- parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java	9 Sep 2003 20:01:23 -0000	1.18
+++ parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java	12 Sep 2003 14:04:57 -0000
@@ -738,13 +738,13 @@
 				target = ((ISymbol)targetParams.next()).getTypeInfo();
 				if( source.equals( target ) ){
 					cost = new Cost( source, target );
-					cost.rank = 0;	//exact match, no cost
+					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 == -1 && !data.forUserDefinedConversion ){
+					if( cost.rank == Cost.NO_MATCH_RANK && !data.forUserDefinedConversion ){
 						temp = checkUserDefinedConversionSequence( source, target );
 						if( temp != null ){
 							cost = temp;
@@ -758,7 +758,9 @@
 			
 			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 < numParams; j++ ){ 
 				if( currFnCost[ j ].rank < 0 ){
 					hasWorse = true;
@@ -766,6 +768,8 @@
 					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 ){
@@ -776,11 +780,15 @@
 					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;
@@ -1091,6 +1099,13 @@
 		}
 		
 		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() ){
@@ -1132,6 +1147,12 @@
 		return cost;
 	}
 	
+	/**
+	 * qualificationConversion
+	 * @param cost
+	 * 
+	 * see spec section 4.4 regarding qualification conversions
+	 */
 	static private void qualificationConversion( Cost cost ){
 		int size = cost.source.hasPtrOperators() ? cost.source.getPtrOperators().size() : 0;
 		int size2 = cost.target.hasPtrOperators() ? cost.target.getPtrOperators().size() : 0;
@@ -1149,6 +1170,7 @@
 			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() ) )
 			{
@@ -1166,7 +1188,7 @@
 				op1 = (TypeInfo.PtrOp) iter1.next();
 				op2 = (TypeInfo.PtrOp) iter2.next();
 				
-				//pointer types are similar
+				//pointer types must be similar
 				if( op1.getType() != op2.getType() ){
 					canConvert = false;
 					break;
@@ -1191,7 +1213,7 @@
 		
 		if( canConvert == true ){
 			cost.qualification = 1;
-			cost.rank = 0;
+			cost.rank = Cost.LVALUE_OR_QUALIFICATION_RANK;
 		} else {
 			cost.qualification = 0;
 		}
@@ -1235,7 +1257,7 @@
 			cost.promotion = 0;
 		}
 		
-		cost.rank = (cost.promotion > 0 ) ? 1 : -1;
+		cost.rank = (cost.promotion > 0 ) ? Cost.PROMOTION_RANK : Cost.NO_MATCH_RANK;
 	}
 	
 	/**
@@ -1269,7 +1291,7 @@
 				//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 = 2;
+					cost.rank = Cost.CONVERSION_RANK;
 					cost.conversion = 1;
 					cost.detail = 2;
 					return;	
@@ -1281,7 +1303,7 @@
 				// 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() ) ){
 					temp = hasBaseClass( (IDerivableContainerSymbol) srcDecl, (IDerivableContainerSymbol) trgDecl );
-					cost.rank = 2;
+					cost.rank = Cost.CONVERSION_RANK;
 					cost.conversion = ( temp > -1 ) ? temp : 0;
 					cost.detail = 1;
 					return;
@@ -1297,7 +1319,7 @@
 				TypeInfo.PtrOp srcPtr =  trg.hasPtrOperators() ? (TypeInfo.PtrOp)trg.getPtrOperators().getFirst() : null;
 				if( trgDecl.isType( srcDecl.getType() ) && srcPtr != null && srcPtr.getType() == TypeInfo.PtrOp.t_memberPointer ){
 					temp = hasBaseClass( (IDerivableContainerSymbol)ptr.getMemberOf(), (IDerivableContainerSymbol)srcPtr.getMemberOf() );
-					cost.rank = 2;
+					cost.rank = Cost.CONVERSION_RANK;
 					cost.detail = 1;
 					cost.conversion = ( temp > -1 ) ? temp : 0;
 					return; 
@@ -1313,7 +1335,7 @@
 				if( trg.isType( TypeInfo.t_bool, TypeInfo.t_int ) ||
 					trg.isType( TypeInfo.t_float, TypeInfo.t_double ) )
 				{
-					cost.rank = 2;
+					cost.rank = Cost.CONVERSION_RANK;
 					cost.conversion = 1;	
 				}
 			}
@@ -1323,8 +1345,12 @@
 	static private Cost checkStandardConversionSequence( TypeInfo source, TypeInfo 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 = 0;
+			cost.rank = Cost.IDENTITY_RANK;
 			return cost;
 		}
 	
@@ -1384,7 +1410,7 @@
 		//conversion operators
 		if( source.getType() == TypeInfo.t_type ){
 			source = getFlatTypeInfo( source );
-			sourceDecl = source.getTypeSymbol();
+			sourceDecl = ( source != null ) ? source.getTypeSymbol() : null;
 			
 			if( sourceDecl != null && (sourceDecl instanceof IContainerSymbol) ){
 				String name = target.toString();
@@ -1409,21 +1435,21 @@
 		}
 		
 		//if both are valid, then the conversion is ambiguous
-		if( constructorCost != null && constructorCost.rank != -1 && 
-			conversionCost != null && conversionCost.rank != -1 )
+		if( constructorCost != null && constructorCost.rank != Cost.NO_MATCH_RANK && 
+			conversionCost != null && conversionCost.rank != Cost.NO_MATCH_RANK )
 		{
 			cost = constructorCost;
-			cost.userDefined = 1;
-			cost.rank = 3;
+			cost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION;	
+			cost.rank = Cost.USERDEFINED_CONVERSION_RANK;
 		} else {
-			if( constructorCost != null && constructorCost.rank != -1 ){
+			if( constructorCost != null && constructorCost.rank != Cost.NO_MATCH_RANK ){
 				cost = constructorCost;
 				cost.userDefined = constructor.hashCode();
-				cost.rank = 3;
-			} else if( conversionCost != null && conversionCost.rank != -1 ){
+				cost.rank = Cost.USERDEFINED_CONVERSION_RANK;
+			} else if( conversionCost != null && conversionCost.rank != Cost.NO_MATCH_RANK ){
 				cost = conversionCost;
 				cost.userDefined = conversion.hashCode();
-				cost.rank = 3;
+				cost.rank = Cost.USERDEFINED_CONVERSION_RANK;
 			} 			
 		}
 		
@@ -1442,20 +1468,19 @@
 		TypeInfo returnInfo = topInfo;
 		TypeInfo info = null;
 		
-		if( topInfo.getType() == TypeInfo.t_type ){
+		if( topInfo.getType() == TypeInfo.t_type && topInfo.getTypeSymbol() != null ){
 			returnInfo = (TypeInfo)new TypeInfo();
 			
 			ISymbol typeSymbol = topInfo.getTypeSymbol();
 			
-			info = topInfo.getTypeSymbol().getTypeInfo();
+			info = typeSymbol.getTypeInfo();
 			
-			while( info.getType() == TypeInfo.t_type || ( info.isForwardDeclaration() && info.getTypeSymbol() != null ) ){
+			while( info.getTypeSymbol() != null && ( info.getType() == TypeInfo.t_type || info.isForwardDeclaration() ) ){
 				typeSymbol = info.getTypeSymbol();
 				
-				//returnInfo.addCVQualifier( info.getCVQualifier() );
 				returnInfo.addPtrOperator( info.getPtrOperators() );	
 				
-				info = info.getTypeSymbol().getTypeInfo();
+				info = typeSymbol.getTypeInfo();
 			}
 			
 			if( info.isType( TypeInfo.t_class, TypeInfo.t_enumeration ) ){
@@ -2038,6 +2063,16 @@
 		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 USERDEFINED_CONVERSION_RANK = 3;
+		
 		public int compare( Cost cost ){
 			int result = 0;
 			
@@ -2049,7 +2084,7 @@
 				if( userDefined == 0 || cost.userDefined == 0 ){
 					return cost.userDefined - userDefined;
 				} else {
-					if( (userDefined == 1 || cost.userDefined == 1) ||
+					if( (userDefined == AMBIGUOUS_USERDEFINED_CONVERSION || cost.userDefined == AMBIGUOUS_USERDEFINED_CONVERSION) ||
 						(userDefined != cost.userDefined ) )
 					{
 						return 0;
@@ -3135,7 +3170,7 @@
 				if( paramType == null ){
 					continue;
 				}
-				
+					
 				ParserSymbolTable.getAssociatedScopes( paramType, associated );
 			
 				//if T is a pointer to a data member of class X, its associated namespaces and classes
Index: ChangeLog
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core.tests/ChangeLog,v
retrieving revision 1.91
diff -u -r1.91 ChangeLog
--- ChangeLog	12 Sep 2003 13:13:45 -0000	1.91
+++ ChangeLog	12 Sep 2003 14:07:09 -0000
@@ -1,3 +1,6 @@
+2003-09-12 Andrew Niefer
+	- added testBadParameterInfo to ParserSymbolTableTest
+
 2003-09-11 Andrew Niefer
 	Created search/SearchTestSuite
 	Added SearchTestSuite to AutomatedIntegrationSuite and removed the individual search tests
Index: parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java,v
retrieving revision 1.16
diff -u -r1.16 ParserSymbolTableTest.java
--- parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java	8 Sep 2003 18:10:55 -0000	1.16
+++ parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java	12 Sep 2003 14:07:10 -0000
@@ -2584,5 +2584,45 @@
 		look = table.getCompilationUnit().unqualifiedFunctionLookup( "f", paramList );
 		assertEquals( look, f );
 	}
+	
+	/**
+	 * 
+	 * @throws Exception
+	 * 
+	 * The general rule is that when you set a TypeInfo's type to be t_type, you 
+	 * should set the type symbol to be something.  This is to test that the function
+	 * resolution can handle a bad typeInfo that has a null symbol without throwing a NPE
+	 */
+	public void testBadParameterInfo() throws Exception{
+		newTable();
+		
+		IParameterizedSymbol f = table.newParameterizedSymbol( "f", TypeInfo.t_function );
+		f.setReturnType( table.newSymbol( "", TypeInfo.t_void ) );
+		
+		IDerivableContainerSymbol a = table.newDerivableContainerSymbol( "A", TypeInfo.t_class );
+		table.getCompilationUnit().addSymbol( a );
+		
+		f.addParameter( a, null, false );
+		
+		table.getCompilationUnit().addSymbol( f );
+		
+		LinkedList paramList = new LinkedList ();
+		
+		TypeInfo param = new TypeInfo( TypeInfo.t_type, 0, null );
+		
+		paramList.add( param );
+		
+		ISymbol look = table.getCompilationUnit().unqualifiedFunctionLookup( "f", paramList );
+		
+		assertEquals( look, null );
+		
+		ISymbol intermediate = table.newSymbol( "", TypeInfo.t_type );
+		
+		param.setTypeSymbol( intermediate );
+		
+		look = table.getCompilationUnit().unqualifiedFunctionLookup( "f", paramList );
+		
+		assertEquals( look, null );
+	}
 }
 

Back to the top