{"record":{"id":"76628e5362947197","repo":"antlr/antlr4","slug":"cannot-handle-relative-paths-containing","errorCode":null,"errorMessage":"Cannot handle relative paths containing '..'","messagePattern":"Cannot handle relative paths containing '\\.\\.'","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java","lineNumber":480,"sourceCode":"\t\tSourceMapping mapping = new SuffixMapping(\"g4\", Collections.<String>emptySet());\n\n\t\t// What are the sets of includes (defaulted or otherwise).\n\t\tSet<String> includes = getIncludesPatterns();\n\n\t\t// Now, to the excludes, we need to add the imports directory\n\t\t// as this is autoscanned for imported grammars and so is auto-excluded from the\n\t\t// set of grammar fields we should be analyzing.\n\t\texcludes.add(\"imports/**\");\n\n\t\tSourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);\n\t\tscan.addSourceMapping(mapping);\n\n\t\treturn scan.getIncludedSources(sourceDirectory, null);\n\t}\n\n\tprivate static String getPackageName(String relativeFolderPath) {\n\t\tif (relativeFolderPath.contains(\"..\")) {\n\t\t\tthrow new UnsupportedOperationException(\"Cannot handle relative paths containing '..'\");\n\t\t}\n\n\t\tList<String> parts = new ArrayList<String>(Arrays.asList(relativeFolderPath.split(\"[/\\\\\\\\\\\\.]+\")));\n\t\twhile (parts.remove(\"\")) {\n\t\t\t// intentionally blank\n\t\t}\n\n\t\treturn Utils.join(parts.iterator(), \".\");\n\t}\n\n    public Set<String> getIncludesPatterns() {\n        if (includes == null || includes.isEmpty()) {\n            return Collections.singleton(\"**/*.g4\");\n        }\n        return includes;\n    }\n\n    private File getDependenciesStatusFile() {","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/antlr4-maven-plugin/src/main/java/org/antlr/mojo/antlr4/Antlr4Mojo.java#L462-L498","documentation":"split(pattern) scans for start/stop delimiter positions; if it finds more start delimiters than stop delimiters, at least one tag was never closed, and chunk extraction cannot proceed, so IllegalArgumentException 'unterminated tag' is thrown. The message echoes the whole pattern to show the offending input.","triggerScenarios":"Patterns like \"<ID + <INT>\" (first '<' unclosed), or custom delimiters where an escape sequence was forgotten; also a stop delimiter accidentally written with different characters than configured.","commonSituations":"Hand-written patterns in tests; patterns built by string concatenation that drop a closing delimiter; languages whose literal text contains the start delimiter (e.g. HTML/XML-like syntaxes with '<'), requiring the escape sequence.","solutions":["Balance every tag: each '<' needs a matching '>'.","Escape literal delimiters in text chunks with the configured escape sequence (default '\\\\' passed as escapeLeft).","If the target language is full of '<', switch delimiters via setDelimiters to something rare like %% %%."],"exampleFix":"// before\nParseTreePattern p = m.compile(\"a < <ID>\", R.expr); // first '<' unterminated\n\n// after\nParseTreePattern p = m.compile(\"a \\\\< <ID>\", R.expr); // escaped literal '<'","handlingStrategy":"try-catch","validationCode":"long starts = pattern.chars().filter(c -> c == '<').count();\nlong stops  = pattern.chars().filter(c -> c == '>').count();\nif (starts > stops) throw new IllegalArgumentException(\"unterminated tag: \" + pattern);","typeGuard":"boolean hasBalancedTags(String p) {\n    return p.chars().filter(c -> c=='<').count() == p.chars().filter(c -> c=='>').count();\n}","tryCatchPattern":"try {\n    pattern = matcher.compile(patternText, ruleIndex);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"unterminated tag\")) {\n        patternText = fixUnescapedDelimiters(patternText);\n        pattern = matcher.compile(patternText, ruleIndex);\n    } else throw e;\n}","preventionTips":["Escape literal '<' with the configured escape sequence.","Balance every tag's delimiters when writing patterns.","Switch to rare custom delimiters for XML-like target languages.","Lint patterns for delimiter balance in CI."],"tags":["antlr","java","parse-tree-pattern","pattern-syntax","delimiters"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}