@@ -22,16 +22,13 @@ namespace Microsoft.OpenApi.Readers
2222 public class ParsingContext
2323 {
2424 private readonly Stack < string > _currentLocation = new Stack < string > ( ) ;
25- private readonly Dictionary < string , IOpenApiReferenceable > _referenceStore = new Dictionary < string , IOpenApiReferenceable > ( ) ;
2625 private readonly Dictionary < string , object > _tempStorage = new Dictionary < string , object > ( ) ;
2726 private IOpenApiVersionService _versionService ;
28-
27+ private readonly Dictionary < string , Stack < string > > _loopStacks = new Dictionary < string , Stack < string > > ( ) ;
2928 internal Dictionary < string , Func < IOpenApiAny , IOpenApiExtension > > ExtensionParsers { get ; set ; } = new Dictionary < string , Func < IOpenApiAny , IOpenApiExtension > > ( ) ;
30-
3129 internal RootNode RootNode { get ; set ; }
3230 internal List < OpenApiTag > Tags { get ; private set ; } = new List < OpenApiTag > ( ) ;
3331
34-
3532 /// <summary>
3633 /// Initiates the parsing process. Not thread safe and should only be called once on a parsing context
3734 /// </summary>
@@ -131,48 +128,6 @@ public string GetLocation()
131128 return "#/" + string . Join ( "/" , _currentLocation . Reverse ( ) . ToArray ( ) ) ;
132129 }
133130
134- /// <summary>
135- /// Gets the referenced object.
136- /// </summary>
137- public IOpenApiReferenceable GetReferencedObject (
138- OpenApiDiagnostic diagnostic ,
139- ReferenceType referenceType ,
140- string referenceString )
141- {
142- _referenceStore . TryGetValue ( referenceString , out var referencedObject ) ;
143-
144- // If reference has already been accessed once, simply return the same reference object.
145- if ( referencedObject != null )
146- {
147- return referencedObject ;
148- }
149-
150- var reference = VersionService . ConvertToOpenApiReference ( referenceString , referenceType ) ;
151-
152- var isReferencedObjectFound = VersionService . TryLoadReference ( this , reference , out referencedObject ) ;
153-
154- if ( isReferencedObjectFound )
155- {
156- // Populate the Reference section of the object, so that the writers
157- // can recognize that this is referencing another object.
158- referencedObject . Reference = reference ;
159- _referenceStore . Add ( referenceString , referencedObject ) ;
160- }
161- else if ( referencedObject != null )
162- {
163- return referencedObject ;
164- }
165- else
166- {
167- diagnostic . Errors . Add (
168- new OpenApiError (
169- GetLocation ( ) ,
170- $ "Cannot resolve the reference { referenceString } ") ) ;
171- }
172-
173- return referencedObject ;
174- }
175-
176131 /// <summary>
177132 /// Gets the value from the temporary storage matching the given key.
178133 /// </summary>
@@ -201,5 +156,52 @@ public void StartObject(string objectName)
201156 {
202157 _currentLocation . Push ( objectName ) ;
203158 }
159+
160+ /// <summary>
161+ /// Maintain history of traversals to avoid stack overflows from cycles
162+ /// </summary>
163+ /// <param name="loopId">Any unique identifier for a stack.</param>
164+ /// <param name="key">Identifier used for current context.</param>
165+ /// <returns>If method returns false a loop was detected and the key is not added.</returns>
166+ public bool PushLoop ( string loopId , string key )
167+ {
168+ Stack < string > stack ;
169+ if ( ! _loopStacks . TryGetValue ( loopId , out stack ) )
170+ {
171+ stack = new Stack < string > ( ) ;
172+ _loopStacks . Add ( loopId , stack ) ;
173+ }
174+
175+ if ( ! stack . Contains ( key ) )
176+ {
177+ stack . Push ( key ) ;
178+ return true ;
179+ } else
180+ {
181+ return false ; // Loop detected
182+ }
183+ }
184+
185+ /// <summary>
186+ /// Reset loop tracking stack
187+ /// </summary>
188+ /// <param name="loopid">Identifier of loop to clear</param>
189+ internal void ClearLoop ( string loopid )
190+ {
191+ _loopStacks [ loopid ] . Clear ( ) ;
192+ }
193+
194+ /// <summary>
195+ /// Exit from the context in cycle detection
196+ /// </summary>
197+ /// <param name="loopid">Identifier of loop</param>
198+ public void PopLoop ( string loopid )
199+ {
200+ if ( _loopStacks [ loopid ] . Count > 0 )
201+ {
202+ _loopStacks [ loopid ] . Pop ( ) ;
203+ }
204+ }
205+
204206 }
205207}
0 commit comments