#!/usr/bin/env python3 """ Scan router.go for Gin radix tree param name conflicts. Gin requires all routes at the same URL position to use the same param name. Strategy: Build a prefix tree, find all positions where multiple param names are used. """ import re with open('/home/yanghao05/Workspace/gochat/internal/router/router.go') as f: lines = f.readlines() # Track Group nesting to build full paths group_stack = [] # list of (var_name, prefix_path) routes = [] # Parse the file line by line for i, line in enumerate(lines): stripped = line.strip() if stripped.startswith('//') or not stripped: continue # Detect Group definition: varName := parent.Group("/path") gmatch = re.match(r'(\w+)\s*:?=\s*(\w+)\.Group\("([^"]+)"\)', stripped) if gmatch: var_name = gmatch.group(1) parent = gmatch.group(2) path = gmatch.group(3) # Find parent prefix parent_prefix = '' for name, prefix in group_stack: if name == parent: parent_prefix = prefix break full_prefix = parent_prefix + path group_stack.append((var_name, full_prefix)) continue # Detect route registration: var.Method("/path", handler) for method in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']: pattern = rf'^(\w+)\.{method}\("([^"]+)"\s*,' rmatch = re.match(pattern, stripped) if rmatch: var_name = rmatch.group(1) path = rmatch.group(2) # Find prefix for this group variable prefix = '' for name, p in group_stack: if name == var_name: prefix = p break full_path = prefix + path routes.append((method, full_path, i+1)) break # Now build a radix-tree-like structure to find conflicts # At each path segment position, track all param names seen tree = {} # key: tuple of segments up to a position -> set of param names at that position for method, path, linenum in routes: segments = [s for s in path.split('/') if s] # skip empty segments for pos, seg in enumerate(segments): if seg.startswith(':'): param_name = seg[1:] prefix_key = '/'.join(segments[:pos]) if prefix_key not in tree: tree[prefix_key] = {} if pos not in tree[prefix_key]: tree[prefix_key][pos] = {} if param_name not in tree[prefix_key][pos]: tree[prefix_key][pos][param_name] = [] tree[prefix_key][pos][param_name].append((method, path, linenum)) # Find conflicts print("=== Gin路由参数名冲突检测 ===\n") conflicts_found = 0 for prefix, positions in sorted(tree.items()): for pos, names_dict in positions.items(): if len(names_dict) > 1: names = sorted(names_dict.keys()) conflicts_found += 1 print(f"冲突 #{conflicts_found}: 前缀 '{prefix}' 位置 {pos}") print(f" 参数名: {names}") for name, refs in names_dict.items(): print(f" :{name} 的使用:") for method, path, linenum in refs[:3]: print(f" Line {linenum}: {method} {path}") if len(refs) > 3: print(f" ... (还有 {len(refs)-3} 条)") print() print(f"总计冲突: {conflicts_found}")