diff --git a/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs
new file mode 100644
index 00000000000..9eb0095ea37
--- /dev/null
+++ b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs
@@ -0,0 +1,30 @@
+using Antlr.Runtime;
+using NHibernate.Hql.Ast.ANTLR;
+using NHibernate.Hql.Ast.ANTLR.Tree;
+using NUnit.Framework;
+
+namespace NHibernate.Test.Hql.Parser
+{
+ [TestFixture]
+ public class HqlParserFixture
+ {
+ [Test]
+ public void HandlesPathWithReservedWords()
+ {
+ Assert.DoesNotThrow(() => Parse("delete from System.Object"));
+ Assert.DoesNotThrow(() => Parse("delete from Object.Object.Object.Object"));
+ }
+
+ private static void Parse(string hql)
+ {
+ var lex = new HqlLexer(new CaseInsensitiveStringStream(hql));
+ var tokens = new CommonTokenStream(lex);
+
+ var parser = new HqlParser(tokens)
+ {
+ TreeAdaptor = new ASTTreeAdaptor(),
+ ParseErrorHandler = new WarningAsErrorReporter()
+ }.statement();
+ }
+ }
+}
diff --git a/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs
new file mode 100644
index 00000000000..5897d670698
--- /dev/null
+++ b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs
@@ -0,0 +1,29 @@
+using Antlr.Runtime;
+using NHibernate.Hql.Ast.ANTLR;
+
+namespace NHibernate.Test.Hql.Parser
+{
+ public class WarningAsErrorReporter : IParseErrorHandler
+ {
+ public void ReportError(RecognitionException e)
+ {
+ throw e;
+ }
+
+ public void ReportError(string s)
+ {
+ throw new QueryException(s);
+ }
+
+ public void ReportWarning(string s)
+ {
+ throw new QueryException(s);
+ }
+
+ public int GetErrorCount() => 0;
+
+ public void ThrowQueryException()
+ {
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj
index a523ac5f94f..a3770c40cbf 100644
--- a/src/NHibernate.Test/NHibernate.Test.csproj
+++ b/src/NHibernate.Test/NHibernate.Test.csproj
@@ -46,6 +46,9 @@
+
+ Hql\Parser\CaseInsensitiveStringStream.cs
+
UtilityTest\AsyncReaderWriterLock.cs
diff --git a/src/NHibernate/Hql/Ast/ANTLR/Hql.g b/src/NHibernate/Hql/Ast/ANTLR/Hql.g
index 364c9142711..fa4d5467f72 100644
--- a/src/NHibernate/Hql/Ast/ANTLR/Hql.g
+++ b/src/NHibernate/Hql/Ast/ANTLR/Hql.g
@@ -695,10 +695,9 @@ constant
path
@init {
-// TODO - need to clean up DotIdent - suspect that DotIdent2 supersedes the other one, but need to do the analysis
-//HandleDotIdent2();
+HandleDotIdents();
}
- : identifier ( DOT^ { WeakKeywords(); } identifier )*
+ : identifier ( DOT^ identifier )*
;
// Wraps the IDENT token from the lexer, in order to provide
diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs
index 35e7a520565..764cccdf873 100644
--- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs
+++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs
@@ -112,6 +112,27 @@ protected override object RecoverFromMismatchedToken(IIntStream input, int ttype
throw new MismatchedTokenException(ttype, input);
}
+ public void HandleDotIdents()
+ {
+ int i = 2;
+
+ while (input.LA(i) == DOT)
+ {
+ var next = input.LT(i + 1);
+ if (next != null)
+ next.Type = IDENT;
+ i += 2;
+ }
+
+ if (input.LA(1) == IDENT || input.LA(2) != DOT)
+ return;
+
+ if (IsPossibleId(input.LT(1)))
+ {
+ input.LT(1).Type = IDENT;
+ }
+ }
+
public void WeakKeywords()
{
int t = input.LA(1);