|
11 | 11 | package com.avaloq.tools.ddk.xtext.scoping; |
12 | 12 |
|
13 | 13 | import java.util.ConcurrentModificationException; |
| 14 | +import java.util.HashSet; |
14 | 15 | import java.util.Iterator; |
15 | 16 | import java.util.Map; |
16 | 17 | import java.util.Set; |
|
27 | 28 | import com.avaloq.tools.ddk.caching.CacheManager; |
28 | 29 | import com.avaloq.tools.ddk.xtext.resource.Messages; |
29 | 30 | import com.google.common.collect.Iterables; |
30 | | -import com.google.common.collect.Sets; |
31 | 31 |
|
32 | 32 |
|
33 | 33 | /** |
|
37 | 37 | public abstract class AbstractRecursiveScope extends AbstractScope { |
38 | 38 |
|
39 | 39 | // CHECKSTYLE:OFF |
40 | | - private static boolean DEBUG = true; |
| 40 | + private static boolean DEBUG = Boolean.getBoolean("com.avaloq.tools.ddk.xtext.scoping.AbstractRecursiveScope.debugCyclicDependency"); //$NON-NLS-1$ |
41 | 41 | // CHECKSTYLE:ON |
42 | 42 |
|
43 | | - private static final String CYCLIC_DEPENDENCY_MESSAGE = "Cyclic dependency detected for \"{0}\"."; //$NON-NLS-1$ |
44 | | - |
45 | 43 | /** |
46 | 44 | * Set is used to trace invocations of {@link #getSingleElement(QualifiedName)} and {@link #getAllContentsByEObject(EObject)}. |
47 | 45 | * A duplicate insertion indicates an infinite recursion, i.e. it would lead to a stack overflow. |
48 | 46 | */ |
49 | | - private final Set<Object> invocationTrace = Sets.newHashSetWithExpectedSize(4); |
| 47 | + private Set<Object> invocationTrace; |
50 | 48 |
|
51 | 49 | /** |
52 | 50 | * Marker for the null value for the lookups to be able to distinguish unsuccessful lookups |
@@ -107,20 +105,29 @@ public AbstractRecursiveScope(final String id, final IScope parent, final boolea |
107 | 105 | @Override |
108 | 106 | public synchronized Iterable<IEObjectDescription> getAllElements() { |
109 | 107 | if (contents == null) { |
110 | | - // contents = super.getAllElements(); TODO super eliminates duplicates using a very inefficient algorithm |
| 108 | + // contents = super.getAllElements() eliminates duplicates using a very inefficient algorithm |
111 | 109 | contents = Iterables.concat(getAllLocalElements(), getParent().getAllElements()); |
112 | 110 | } |
113 | 111 | return contents; |
114 | 112 | } |
115 | 113 |
|
| 114 | + private void addInvocationTrace(final Object object) { |
| 115 | + if (invocationTrace == null) { |
| 116 | + invocationTrace = new HashSet<>(); |
| 117 | + } |
| 118 | + if (!invocationTrace.add(object)) { |
| 119 | + throw new IllegalStateException(Messages.bind("Cyclic dependency detected for \"{0}\".", String.valueOf(object))); //$NON-NLS-1$ |
| 120 | + } |
| 121 | + } |
| 122 | + |
116 | 123 | @Override |
117 | 124 | public synchronized IEObjectDescription getSingleElement(final QualifiedName name) { // NOPMD NPathComplexity |
118 | 125 | if (name == null) { |
119 | 126 | throw new IllegalArgumentException("Null name in getContentByName"); //$NON-NLS-1$ |
120 | 127 | } |
121 | 128 | try { |
122 | | - if (DEBUG && !invocationTrace.add(name)) { |
123 | | - throw new IllegalStateException(Messages.bind(CYCLIC_DEPENDENCY_MESSAGE, String.valueOf(name))); |
| 129 | + if (DEBUG) { |
| 130 | + addInvocationTrace(name); |
124 | 131 | } |
125 | 132 | final QualifiedName lookupName = isIgnoreCase() ? name.toLowerCase() : name; // NOPMD UseLocaleWithCaseConversions |
126 | 133 | IEObjectDescription result = nameCache.get(lookupName); |
@@ -153,8 +160,6 @@ public synchronized IEObjectDescription getSingleElement(final QualifiedName nam |
153 | 160 | } |
154 | 161 | if (result == null) { |
155 | 162 | nameCache.put(lookupName, NULL_DESCRIPTION); |
156 | | - // } else { |
157 | | - // ScopeTrace.addTrace(result, getId()); |
158 | 163 | } |
159 | 164 | return result; |
160 | 165 | } catch (ConcurrentModificationException e) { |
@@ -185,9 +190,10 @@ private void reset() { |
185 | 190 | @Override |
186 | 191 | public synchronized IEObjectDescription getSingleElement(final EObject object) { |
187 | 192 | try { |
188 | | - if (DEBUG && !invocationTrace.add(object)) { |
189 | | - throw new IllegalStateException(Messages.bind(CYCLIC_DEPENDENCY_MESSAGE, String.valueOf(object))); |
| 193 | + if (DEBUG) { |
| 194 | + addInvocationTrace(object); |
190 | 195 | } |
| 196 | + |
191 | 197 | final URI key = EcoreUtil.getURI(object); |
192 | 198 | IEObjectDescription result = objectCache.get(key); |
193 | 199 | if (result == NULL_DESCRIPTION) { // NOPMD CompareObjectsWithEquals |
|
0 commit comments