@@ -320,8 +320,19 @@ module Templating {
320320 */
321321 string getStem ( ) { result = getBaseName ( ) .regexpCapture ( "(.*?)(?:\\.([^.]*))?" , 1 ) }
322322
323+ /** Gets a template string with all leading `../` sequences resolved. */
324+ private TemplateFileReferenceString resolveUpwardTraversal ( ) {
325+ exists ( UpwardTraversalSuffix up |
326+ this = up .getOriginal ( ) and
327+ result = up .( TemplateFileReferenceString ) .resolveUpwardTraversal ( )
328+ )
329+ or
330+ not this = any ( UpwardTraversalSuffix up ) .getOriginal ( ) and
331+ result = this
332+ }
333+
323334 /** Gets the template file referenced by this string. */
324- final TemplateFile getTemplateFile ( ) { result = getBestMatchingTarget ( this ) }
335+ final TemplateFile getTemplateFile ( ) { result = getBestMatchingTarget ( this . resolveUpwardTraversal ( ) ) }
325336 }
326337
327338 /** The value of a template reference node, as a template reference string. */
@@ -333,6 +344,24 @@ module Templating {
333344 override Folder getContextFolder ( ) { result = r .getFile ( ) .getParentContainer ( ) }
334345 }
335346
347+ /** The `X` in a path of form `../X`, treated as a separate path string with a different context folder. */
348+ private class UpwardTraversalSuffix extends TemplateFileReferenceString {
349+ TemplateFileReferenceString original ;
350+
351+ UpwardTraversalSuffix ( ) {
352+ original = "../" + this
353+ }
354+
355+ override Folder getContextFolder ( ) {
356+ result = original .getContextFolder ( ) .getParentContainer ( )
357+ }
358+
359+ /** Gets the original string including the `../` prefix. */
360+ TemplateFileReferenceString getOriginal ( ) {
361+ result = original
362+ }
363+ }
364+
336365 /**
337366 * Gets a "fingerprint" for the given template file, which is used to references
338367 * that might refer to it (for pruning purposes only).
0 commit comments