{"record":{"id":"1312c9b6932f83fa","repo":"antlr/antlr4","slug":"patterntree-cannot-be-null-1312c9","errorCode":null,"errorMessage":"patternTree cannot be null","messagePattern":"patternTree cannot be null","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs","lineNumber":399,"sourceCode":"        /// which does not match\n        /// a corresponding node in\n        /// <paramref name=\"patternTree\"/>\n        /// , or\n        /// <see langword=\"null\"/>\n        /// if the match\n        /// was successful. The specific node returned depends on the matching\n        /// algorithm used by the implementation, and may be overridden.\n        /// </returns>\n        [return: Nullable]\n        protected internal virtual IParseTree MatchImpl(IParseTree tree, IParseTree patternTree, MultiMap<string, IParseTree> labels)\n        {\n            if (tree == null)\n            {\n                throw new ArgumentException(\"tree cannot be null\");\n            }\n            if (patternTree == null)\n            {\n                throw new ArgumentException(\"patternTree cannot be null\");\n            }\n            // x and <ID>, x and y, or x and x; or could be mismatched types\n            if (tree is ITerminalNode && patternTree is ITerminalNode)\n            {\n                ITerminalNode t1 = (ITerminalNode)tree;\n                ITerminalNode t2 = (ITerminalNode)patternTree;\n                IParseTree mismatchedNode = null;\n                // both are tokens and they have same type\n                if (t1.Symbol.Type == t2.Symbol.Type)\n                {\n                    if (t2.Symbol is TokenTagToken)\n                    {\n                        // x and <ID>\n                        TokenTagToken tokenTagToken = (TokenTagToken)t2.Symbol;\n                        // track label->list-of-nodes for both token name and label (if any)\n\n                        labels.Map(tokenTagToken.TokenName, tree);\n                        if (tokenTagToken.Label != null)","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs#L381-L417","documentation":"ParseTreePatternMatcher.MatchImpl rejects a null patternTree argument. The pattern tree is the compiled form of the pattern string produced by ParseTreePatternMatcher.Compile; the recursion always supplies it, so a null means MatchImpl was invoked directly or from an override that lost the pattern tree.","triggerScenarios":"Calling MatchImpl(tree, null, labels) directly; an override that stores the pattern tree in a field initialized to null instead of forwarding the parameter.","commonSituations":"Custom matcher subclasses that restructure the recursion; caching pattern trees in a dictionary that returns null on a miss and forwarding the miss; refactors between Java and C# runtimes dropping an argument.","solutions":["Forward the patternTree parameter that MatchImpl receives when recursing into children.","Ensure pattern trees come from ParseTreePatternMatcher.Compile(...) / parser.CompileParseTreePattern(...) and cache misses are compiled, not skipped.","Use the public match API instead of MatchImpl."],"exampleFix":"// before\nbase.MatchImpl(tree.GetChild(i), cachedPattern /* null on miss */, labels);\n\n// after\nif (!cache.TryGetValue(key, out var ptree)) { ptree = Compile(key); cache[key] = ptree; }\nbase.MatchImpl(tree.GetChild(i), ptree, labels);","handlingStrategy":"validation","validationCode":"var ptree = patternTree ?? throw new InvalidOperationException(\"pattern tree not compiled\");\nvar r = MatchImpl(tree, ptree, labels);","typeGuard":"static bool HasPatternTree(IParseTree p) => p != null;","tryCatchPattern":null,"preventionTips":["Forward the patternTree parameter in overrides; do not substitute possibly-null fields.","Compile-and-cache pattern trees so lookups never yield null."],"tags":["antlr","csharp","pattern-matcher","null-check","match"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}