From 623f4b69aec419df2311ea1b0d4e92492178b1b9 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Sat, 15 Jan 2022 16:56:09 +0100 Subject: [PATCH] fixed endless recursion in context analysis when context analysis is needed and an element in context has multiple cardinality and contains empty paths (e.g. ?-quantified) the quantified element will be recursed endlessly without the token analysis path even being done (since there is always an empty path) - this also applies to unordered groups. recognizing empty paths is not trivial because of recursive rules. solution: save "call stack" (actually just a set of visited elements) during recursions in context analysis. if an element is seen multiple times we check if there is any progress in the analysis paths. if not this is an endless recursion -> throw exception --- ...cursionPathInContextAnalysisException.java | 47 +++++++++++++++++++ .../hoisting/pathAnalysis/TokenAnalysis.java | 13 ++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/EmptyRecursionPathInContextAnalysisException.java diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/EmptyRecursionPathInContextAnalysisException.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/EmptyRecursionPathInContextAnalysisException.java new file mode 100644 index 000000000..8dc175c03 --- /dev/null +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/exceptions/EmptyRecursionPathInContextAnalysisException.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2022 itemis AG (http://www.itemis.eu) and others. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions; + +import org.eclipse.xtext.AbstractRule; + +/** + * @author overflow - Initial contribution and API + */ +public class EmptyRecursionPathInContextAnalysisException extends HoistingException { + private static final long serialVersionUID = 3820353828411603508L; + + public EmptyRecursionPathInContextAnalysisException() { + super(); + } + + public EmptyRecursionPathInContextAnalysisException(String message, AbstractRule rule) { + super(message, rule); + } + + public EmptyRecursionPathInContextAnalysisException(String message, Throwable cause, AbstractRule rule) { + super(message, cause, rule); + } + + public EmptyRecursionPathInContextAnalysisException(String message, Throwable cause) { + super(message, cause); + } + + public EmptyRecursionPathInContextAnalysisException(String message) { + super(message); + } + + public EmptyRecursionPathInContextAnalysisException(Throwable cause, AbstractRule rule) { + super(cause, rule); + } + + public EmptyRecursionPathInContextAnalysisException(Throwable cause) { + super(cause); + } + +} diff --git a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java index d64d3a2d2..a4604bd51 100644 --- a/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java +++ b/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/parser/antlr/hoisting/pathAnalysis/TokenAnalysis.java @@ -36,6 +36,7 @@ import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.UnorderedGroup; import org.eclipse.xtext.util.XtextSwitch; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.HoistingConfiguration; +import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.EmptyRecursionPathInContextAnalysisException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.NestedPrefixAlternativesException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.SymbolicAnalysisFailedException; import org.eclipse.xtext.xtext.generator.parser.antlr.hoisting.exceptions.TokenAnalysisAbortedException; @@ -153,6 +154,10 @@ public class TokenAnalysis { } private TokenAnalysisPaths getTokenPathsContext(AbstractElement last, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops) { + return getTokenPathsContext(last, prefix, shortcutEndlessLoops, new HashSet<>()); + } + + private TokenAnalysisPaths getTokenPathsContext(AbstractElement last, TokenAnalysisPaths prefix, boolean shortcutEndlessLoops, Set callStack) { log.info("get context for: " + abstractElementToShortString(last)); List context = getNextElementsInContext(last); @@ -170,9 +175,15 @@ public class TokenAnalysis { for (AbstractElement element : context) { log.info("context element: " + abstractElementToShortString(element)); TokenAnalysisPaths path = new TokenAnalysisPaths(prefix); + path.resetProgress(); path = getTokenPaths(element, path, false, false, shortcutEndlessLoops); if (!path.isDone() && element != null) { - path = getTokenPathsContext(element, path, shortcutEndlessLoops); + if (callStack.contains(element) && !path.hasProgress()) { + throw new EmptyRecursionPathInContextAnalysisException("no progress in recursion"); + } + Set localCallStack = new HashSet<>(callStack); + localCallStack.add(element); + path = getTokenPathsContext(element, path, shortcutEndlessLoops, localCallStack); } if (path.isDone()) { result = result.merge(path);