From 9a4acd4d05683ed39a6b59398d8c27485c1dead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= Date: Tue, 23 Jan 2018 21:14:36 +0100 Subject: [PATCH 1/2] Catch practices: avoid losing catched exception information. All catches have been reviewed for avoiding losing original exception information: * When another exception is raised, it should embed the original one as an inner exception. * Otherwise when re-thrown, it should be done without altering its original stack-trace. Preferred way is of course to use "throw;" in the catch clause without specifying the exception, but otherwise ReflectHelper provide a way to preserve the stack-trace. * Otherwise it should be transmitted to the logger. Some cases still do not follow this pattern for avoiding being too noisy, like "Try" utilities, failure in closing an already failed object, some "implemented by exception" features, ... --- .../Async/Cache/StandardQueryCache.cs | 4 +- .../Default/DefaultMergeEventListener.cs | 4 +- .../Async/Impl/SessionFactoryImpl.cs | 1 + src/NHibernate/Cache/StandardQueryCache.cs | 4 +- src/NHibernate/Cfg/SettingsFactory.cs | 4 +- .../Cfg/XmlHbmBinding/ClassBinder.cs | 4 +- .../AbstractPersistentCollection.cs | 6 ++- .../Engine/StatefulPersistenceContext.cs | 4 +- .../Default/DefaultMergeEventListener.cs | 4 +- src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs | 2 + src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs | 2 +- .../Hql/Ast/ANTLR/QuerySyntaxException.cs | 9 ++-- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 2 - .../Hql/Ast/ANTLR/Tree/FromElement.cs | 3 +- .../Hql/Util/SessionFactoryHelper.cs | 16 +++--- .../Id/IdentifierGeneratorFactory.cs | 4 +- src/NHibernate/Impl/SessionFactoryImpl.cs | 9 ++-- src/NHibernate/Mapping/Collection.cs | 4 +- src/NHibernate/Mapping/PersistentClass.cs | 4 +- .../Entity/AbstractEntityPersister.cs | 4 +- src/NHibernate/QueryException.cs | 15 ++++++ src/NHibernate/StaleObjectStateException.cs | 12 ++++- src/NHibernate/StaleStateException.cs | 5 +- src/NHibernate/Util/ReflectHelper.cs | 53 ++++++++++--------- 24 files changed, 109 insertions(+), 70 deletions(-) diff --git a/src/NHibernate/Async/Cache/StandardQueryCache.cs b/src/NHibernate/Async/Cache/StandardQueryCache.cs index 471abc23ede..4be0df5e3f5 100644 --- a/src/NHibernate/Async/Cache/StandardQueryCache.cs +++ b/src/NHibernate/Async/Cache/StandardQueryCache.cs @@ -115,14 +115,14 @@ public async Task GetAsync(QueryKey key, ICacheAssembler[] returnTypes, b result.Add(await (TypeHelper.AssembleAsync((object[])cacheable[i], returnTypes, session, null, cancellationToken)).ConfigureAwait(false)); } } - catch (UnresolvableObjectException) + catch (UnresolvableObjectException ex) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state - Log.Debug("could not reassemble cached result set"); + Log.Debug(ex, "could not reassemble cached result set"); await (_queryCache.RemoveAsync(key, cancellationToken)).ConfigureAwait(false); return null; } diff --git a/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs index 047ea413ba3..40848b4f356 100644 --- a/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultMergeEventListener.cs @@ -263,11 +263,11 @@ private async Task MergeTransientEntityAsync(object entity, string entit if (((EventCache)copyCache).IsOperatedOn(propertyFromEntity)) { - log.Info("property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); + log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); } else { - log.Info("property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); + log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); } // continue...; we'll find out if it ends up not getting saved later diff --git a/src/NHibernate/Async/Impl/SessionFactoryImpl.cs b/src/NHibernate/Async/Impl/SessionFactoryImpl.cs index 7f5a7a7cce2..a82826eae6c 100644 --- a/src/NHibernate/Async/Impl/SessionFactoryImpl.cs +++ b/src/NHibernate/Async/Impl/SessionFactoryImpl.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Data.Common; using System.Linq; using System.Runtime.Serialization; diff --git a/src/NHibernate/Cache/StandardQueryCache.cs b/src/NHibernate/Cache/StandardQueryCache.cs index cce2de498d0..dde9313a90b 100644 --- a/src/NHibernate/Cache/StandardQueryCache.cs +++ b/src/NHibernate/Cache/StandardQueryCache.cs @@ -133,14 +133,14 @@ public IList Get(QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyL result.Add(TypeHelper.Assemble((object[])cacheable[i], returnTypes, session, null)); } } - catch (UnresolvableObjectException) + catch (UnresolvableObjectException ex) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state - Log.Debug("could not reassemble cached result set"); + Log.Debug(ex, "could not reassemble cached result set"); _queryCache.Remove(key); return null; } diff --git a/src/NHibernate/Cfg/SettingsFactory.cs b/src/NHibernate/Cfg/SettingsFactory.cs index 7ff1cad18ac..612ac4a2acb 100644 --- a/src/NHibernate/Cfg/SettingsFactory.cs +++ b/src/NHibernate/Cfg/SettingsFactory.cs @@ -62,9 +62,9 @@ public Settings BuildSettings(IDictionary properties) { sqlExceptionConverter = SQLExceptionConverterFactory.BuildSQLExceptionConverter(dialect, properties); } - catch (HibernateException) + catch (HibernateException he) { - log.Warn("Error building SQLExceptionConverter; using minimal converter"); + log.Warn(he, "Error building SQLExceptionConverter; using minimal converter"); sqlExceptionConverter = SQLExceptionConverterFactory.BuildMinimalSQLExceptionConverter(); } settings.SqlExceptionConverter = sqlExceptionConverter; diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs index 4efd92ff782..516af805efc 100644 --- a/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs +++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs @@ -371,9 +371,9 @@ protected void BindAnyMeta(IAnyMapping anyMapping, Any model) string entityName = GetClassName(metaValue.@class, mappings); values[value] = entityName; } - catch (InvalidCastException) + catch (InvalidCastException ice) { - throw new MappingException("meta-type was not an IDiscriminatorType: " + metaType.Name); + throw new MappingException("meta-type was not an IDiscriminatorType: " + metaType.Name, ice); } catch (HibernateException he) { diff --git a/src/NHibernate/Collection/AbstractPersistentCollection.cs b/src/NHibernate/Collection/AbstractPersistentCollection.cs index c3e1a499bcb..a187d665464 100644 --- a/src/NHibernate/Collection/AbstractPersistentCollection.cs +++ b/src/NHibernate/Collection/AbstractPersistentCollection.cs @@ -61,9 +61,11 @@ public object Current { return enclosingInstance.operationQueue[position].AddedInstance; } - catch (IndexOutOfRangeException) + catch (IndexOutOfRangeException ex) { - throw new InvalidOperationException(); + throw new InvalidOperationException( + "MoveNext as not been called or its last call has yielded false (meaning the enumerator is beyond the end of the enumeration).", + ex); } } } diff --git a/src/NHibernate/Engine/StatefulPersistenceContext.cs b/src/NHibernate/Engine/StatefulPersistenceContext.cs index 27f62db3477..cdb75ca6a7d 100644 --- a/src/NHibernate/Engine/StatefulPersistenceContext.cs +++ b/src/NHibernate/Engine/StatefulPersistenceContext.cs @@ -1439,7 +1439,7 @@ void IDeserializationCallback.OnDeserialization(object sender) } catch (HibernateException he) { - throw new InvalidOperationException(he.Message); + throw new InvalidOperationException(he.Message, he); } } @@ -1467,7 +1467,7 @@ void IDeserializationCallback.OnDeserialization(object sender) } catch (MappingException me) { - throw new InvalidOperationException(me.Message); + throw new InvalidOperationException(me.Message, me); } } } diff --git a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs index 9803fb3fd43..b304bd16512 100644 --- a/src/NHibernate/Event/Default/DefaultMergeEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultMergeEventListener.cs @@ -266,11 +266,11 @@ private object MergeTransientEntity(object entity, string entityName, object req if (((EventCache)copyCache).IsOperatedOn(propertyFromEntity)) { - log.Info("property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); + log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); } else { - log.Info("property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); + log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity); } // continue...; we'll find out if it ends up not getting saved later diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index 393af308102..55e8912babe 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -2,6 +2,7 @@ using Antlr.Runtime; using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Util; using IToken = Antlr.Runtime.IToken; using RecognitionException = Antlr.Runtime.RecognitionException; @@ -418,6 +419,7 @@ public IASTNode HandleIdentifierError(IToken token, RecognitionException ex) } // Otherwise, handle the error normally. + ReflectHelper.PreserveStackTrace(ex); throw ex; } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs index b3084afcb21..26a96899fc0 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs @@ -1097,7 +1097,7 @@ private void HandleWithFragment(FromElement fromElement, IASTNode hqlWithNode) } catch (Exception e) { - throw new SemanticException(e.Message); + throw new SemanticException(e.Message, e); } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs b/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs index c81e9dc34c8..252a99416f5 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QuerySyntaxException.cs @@ -10,6 +10,7 @@ public class QuerySyntaxException : QueryException { protected QuerySyntaxException() {} public QuerySyntaxException(string message, string hql) : base(message, hql) {} + public QuerySyntaxException(string message, string hql, Exception inner) : base(message, hql, inner) {} public QuerySyntaxException(string message) : base(message) {} public QuerySyntaxException(string message, Exception inner) : base(message, inner) {} @@ -24,9 +25,9 @@ public static QuerySyntaxException Convert(RecognitionException e) public static QuerySyntaxException Convert(RecognitionException e, string hql) { string positionInfo = e.Line > 0 && e.CharPositionInLine > 0 - ? " near line " + e.Line + ", column " + e.CharPositionInLine - : ""; - return new QuerySyntaxException(e.Message + positionInfo, hql); + ? " near line " + e.Line + ", column " + e.CharPositionInLine + : ""; + return new QuerySyntaxException(e.Message + positionInfo, hql, e); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 9f0a412921d..9640f44a7ff 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -362,8 +362,6 @@ private void DoCompile(IDictionary replacements, bool shallow, S } catch ( RecognitionException e ) { - // we do not actually propogate ANTLRExceptions as a cause, so - // log it here for diagnostic purposes if ( log.IsInfoEnabled() ) { log.Info(e, "converted antlr.RecognitionException"); diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index cb33b0a6052..39a9f8a8164 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -544,11 +544,12 @@ public void HandlePropertyBeingDereferenced(IType propertySource, string propert _dereferencedBySuperclassProperty = true; } } - catch (QueryException) + catch (QueryException ex) { // ignore it; the incoming property could not be found so we // cannot be sure what to do here. At the very least, the // safest is to simply not apply any dereference toggling... + Log.Info(ex, "Unable to find property {0}, no dereference will be handled for it.", propertyName); } } } diff --git a/src/NHibernate/Hql/Util/SessionFactoryHelper.cs b/src/NHibernate/Hql/Util/SessionFactoryHelper.cs index 0fa798703e1..adbda34b64a 100644 --- a/src/NHibernate/Hql/Util/SessionFactoryHelper.cs +++ b/src/NHibernate/Hql/Util/SessionFactoryHelper.cs @@ -87,13 +87,13 @@ public IQueryableCollection GetCollectionPersister(String role) { return (IQueryableCollection)sfi.GetCollectionPersister(role); } - catch (InvalidCastException) + catch (InvalidCastException ice) { - throw new QueryException("collection is not queryable: " + role); + throw new QueryException("collection is not queryable: " + role, ice); } - catch (Exception) + catch (Exception ex) { - throw new QueryException("collection not found: " + role); + throw new QueryException("collection not found: " + role, ex); } } @@ -186,15 +186,15 @@ public IQueryableCollection RequireQueryableCollection(String role) } return queryableCollection; } - catch (InvalidCastException) + catch (InvalidCastException ice) { throw new QueryException( - "collection role is not queryable: " + role); + "collection role is not queryable: " + role, ice); } - catch (Exception) + catch (Exception ex) { throw new QueryException("collection role not found: " - + role); + + role, ex); } } } diff --git a/src/NHibernate/Id/IdentifierGeneratorFactory.cs b/src/NHibernate/Id/IdentifierGeneratorFactory.cs index 5f89fcbd516..c90ce69f956 100644 --- a/src/NHibernate/Id/IdentifierGeneratorFactory.cs +++ b/src/NHibernate/Id/IdentifierGeneratorFactory.cs @@ -309,9 +309,9 @@ public static System.Type GetIdentifierGeneratorClass(string strategy, Dialect.D clazz = ReflectHelper.ClassForName(strategy); } } - catch (Exception) + catch (Exception ex) { - throw new IdentifierGenerationException("Could not interpret id generator strategy: " + strategy); + throw new IdentifierGenerationException("Could not interpret id generator strategy: " + strategy, ex); } return clazz; } diff --git a/src/NHibernate/Impl/SessionFactoryImpl.cs b/src/NHibernate/Impl/SessionFactoryImpl.cs index 801a419825e..c66bf78baa4 100644 --- a/src/NHibernate/Impl/SessionFactoryImpl.cs +++ b/src/NHibernate/Impl/SessionFactoryImpl.cs @@ -205,9 +205,10 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings SchemaMetadataUpdater.QuoteTableAndColumns(cfg, Dialect); } } - catch (NotSupportedException) + catch (NotSupportedException ex) { - // Ignore if the Dialect does not provide DataBaseSchema + // Ignore if the Dialect does not provide DataBaseSchema + log.Warn(ex, "Dialect does not provide DataBaseSchema, but keywords import or auto quoting is enabled."); } #region Caches @@ -339,9 +340,9 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings { uuid = (string)UuidGenerator.Generate(null, null); } - catch (Exception) + catch (Exception ex) { - throw new AssertionFailure("Could not generate UUID"); + throw new AssertionFailure("Could not generate UUID", ex); } SessionFactoryObjectFactory.AddInstance(uuid, name, this, properties); diff --git a/src/NHibernate/Mapping/Collection.cs b/src/NHibernate/Mapping/Collection.cs index 49677325626..c1b6d1eda12 100644 --- a/src/NHibernate/Mapping/Collection.cs +++ b/src/NHibernate/Mapping/Collection.cs @@ -154,9 +154,9 @@ public object Comparer { comparer = Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(ComparerClassName)); } - catch + catch (Exception ex) { - throw new MappingException("Could not instantiate comparator class [" + ComparerClassName + "] for collection " + Role); + throw new MappingException("Could not instantiate comparator class [" + ComparerClassName + "] for collection " + Role, ex); } } return comparer; diff --git a/src/NHibernate/Mapping/PersistentClass.cs b/src/NHibernate/Mapping/PersistentClass.cs index 770f3755a64..b63a60a3e09 100644 --- a/src/NHibernate/Mapping/PersistentClass.cs +++ b/src/NHibernate/Mapping/PersistentClass.cs @@ -890,9 +890,9 @@ private Property GetRecursiveProperty(string propertyPath, IEnumerable } } } - catch (MappingException) + catch (MappingException ex) { - throw new MappingException("property [" + propertyPath + "] not found on entity [" + EntityName + "]"); + throw new MappingException("property [" + propertyPath + "] not found on entity [" + EntityName + "]", ex); } return property; diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index d33555c5b93..403dc578d8a 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -2206,14 +2206,14 @@ protected bool Check(int rows, object id, int tableNumber, IExpectation expectat { expectation.VerifyOutcomeNonBatched(rows, statement); } - catch (StaleStateException) + catch (StaleStateException sse) { if (!IsNullableTable(tableNumber)) { if (Factory.Statistics.IsStatisticsEnabled) Factory.StatisticsImplementor.OptimisticFailure(EntityName); - throw new StaleObjectStateException(EntityName, id); + throw new StaleObjectStateException(EntityName, id, sse); } } catch (TooManyRowsAffectedException ex) diff --git a/src/NHibernate/QueryException.cs b/src/NHibernate/QueryException.cs index 5d3c33476ab..ff16cad0489 100644 --- a/src/NHibernate/QueryException.cs +++ b/src/NHibernate/QueryException.cs @@ -46,6 +46,21 @@ public QueryException(string message, string queryString) : base(message) this.queryString = queryString; } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + /// The query that contains the error. + /// + /// The exception that is the cause of the current exception. If the innerException parameter + /// is not a null reference, the current exception is raised in a catch block that handles + /// the inner exception. + /// + public QueryException(string message, string queryString, Exception innerException) : base(message, innerException) + { + this.queryString = queryString; + } + /// /// Initializes a new instance of the class. /// diff --git a/src/NHibernate/StaleObjectStateException.cs b/src/NHibernate/StaleObjectStateException.cs index 9cd865cb323..b53e0155f53 100644 --- a/src/NHibernate/StaleObjectStateException.cs +++ b/src/NHibernate/StaleObjectStateException.cs @@ -23,7 +23,17 @@ public class StaleObjectStateException : StaleStateException /// The EntityName that NHibernate was trying to update in the database. /// The identifier of the object that is stale. public StaleObjectStateException(string entityName, object identifier) - : base("Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)") + : this(entityName, identifier, null) + { + } + /// + /// Initializes a new instance of the class. + /// + /// The EntityName that NHibernate was trying to update in the database. + /// The identifier of the object that is stale. + /// The original exception having triggered this exception. + public StaleObjectStateException(string entityName, object identifier, Exception innerException) + : base("Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)", innerException) { this.entityName = entityName; this.identifier = identifier; diff --git a/src/NHibernate/StaleStateException.cs b/src/NHibernate/StaleStateException.cs index 8916a2ca520..2a08cc4e9be 100644 --- a/src/NHibernate/StaleStateException.cs +++ b/src/NHibernate/StaleStateException.cs @@ -9,10 +9,13 @@ public class StaleStateException : HibernateException public StaleStateException(string message) : base(message) { } + public StaleStateException(string message, Exception innerException) : base(message, innerException) + { + } protected StaleStateException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Util/ReflectHelper.cs b/src/NHibernate/Util/ReflectHelper.cs index e821e966c24..b7b159025e6 100644 --- a/src/NHibernate/Util/ReflectHelper.cs +++ b/src/NHibernate/Util/ReflectHelper.cs @@ -602,6 +602,18 @@ public static Exception UnwrapTargetInvocationException(TargetInvocationExceptio return ex.InnerException; } + /// + /// Ensures an exception current stack-trace will be preserved if the exception is explicitly rethrown. + /// + /// + /// The which current stack-trace is to be preserved in case of explicit rethrow. + /// + /// The unwrapped exception. + internal static void PreserveStackTrace(Exception ex) + { + Exception_InternalPreserveStackTrace.Invoke(ex, Array.Empty()); + } + /// /// Try to find a method in a given type. /// @@ -645,34 +657,27 @@ private static MethodInfo SafeGetMethod(System.Type type, MethodInfo method, Sys List typesToSearch = new List(); MethodInfo foundMethod = null; - try - { - typesToSearch.Add(type); - - if (type.IsInterface) - { - // Methods on parent interfaces are not actually inherited - // by child interfaces, so we have to use GetInterfaces to - // identify any parent interfaces that may contain the - // method implementation - System.Type[] inheritedInterfaces = type.GetInterfaces(); - typesToSearch.AddRange(inheritedInterfaces); - } + typesToSearch.Add(type); + + if (type.IsInterface) + { + // Methods on parent interfaces are not actually inherited + // by child interfaces, so we have to use GetInterfaces to + // identify any parent interfaces that may contain the + // method implementation + System.Type[] inheritedInterfaces = type.GetInterfaces(); + typesToSearch.AddRange(inheritedInterfaces); + } - foreach (System.Type typeToSearch in typesToSearch) + foreach (System.Type typeToSearch in typesToSearch) + { + MethodInfo result = typeToSearch.GetMethod(method.Name, bindingFlags, null, tps, null); + if (result != null) { - MethodInfo result = typeToSearch.GetMethod(method.Name, bindingFlags, null, tps, null); - if (result != null) - { - foundMethod = result; - break; - } + foundMethod = result; + break; } } - catch (Exception) - { - throw; - } return foundMethod; } From 258260ca269489b4572c55de8de75c157c24ebec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= Date: Wed, 24 Jan 2018 11:36:20 +0100 Subject: [PATCH 2/2] Switching a log to Debug. --- src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index 39a9f8a8164..d352ba4532b 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -549,7 +549,7 @@ public void HandlePropertyBeingDereferenced(IType propertySource, string propert // ignore it; the incoming property could not be found so we // cannot be sure what to do here. At the very least, the // safest is to simply not apply any dereference toggling... - Log.Info(ex, "Unable to find property {0}, no dereference will be handled for it.", propertyName); + Log.Debug(ex, "Unable to find property {0}, no dereference will be handled for it.", propertyName); } } }