|
44 | 44 | # Example: #loc20 = loc(#loc16) |
45 | 45 | ALIAS_SIMPLE_PATTERN = re.compile(r"#loc(\d+)\s*=\s*loc\(\s*#loc(\d*)\s*\)") |
46 | 46 |
|
| 47 | +# Callsite loc definitions in TTIR/TTGIR |
| 48 | +# Example: #loc220 = loc(callsite(#loc57 at #loc190)) |
| 49 | +# Captures: loc_id, callee_loc_id, caller_loc_id |
| 50 | +# Note: Uses (\d*) to match optional numbers (for bare #loc references) |
| 51 | +CALLSITE_PATTERN = re.compile( |
| 52 | + r"#loc(\d+)\s*=\s*loc\(\s*callsite\(\s*#loc(\d*)\s+at\s+#loc(\d*)\s*\)\s*\)" |
| 53 | +) |
| 54 | + |
47 | 55 |
|
48 | 56 | def extract_loc_definitions(ir_content: str) -> Dict[str, Dict[str, Any]]: |
49 | 57 | """ |
@@ -141,6 +149,50 @@ def resolve_alias(current_id: str) -> Dict[str, Any]: |
141 | 149 | for alias_id, target_id in alias_map.items(): |
142 | 150 | if alias_id not in locations: |
143 | 151 | resolve_alias(alias_id) |
| 152 | + |
| 153 | + # Collect callsite definitions |
| 154 | + callsite_defs = [] |
| 155 | + for i, line in enumerate(ir_content.split("\n"), start=1): |
| 156 | + if m := CALLSITE_PATTERN.search(line): |
| 157 | + loc_id, callee_id, caller_id = m.groups() |
| 158 | + # Empty strings map to main loc key "" |
| 159 | + callsite_defs.append((loc_id, callee_id or "", caller_id or "", i)) |
| 160 | + |
| 161 | + # Resolve callsite definitions |
| 162 | + # A callsite inherits the location from its callee (the code being called) |
| 163 | + # and stores a reference to its caller (the code doing the calling) |
| 164 | + for loc_id, callee_id, caller_id, def_line in callsite_defs: |
| 165 | + if loc_id not in locations: # Avoid overwriting existing definitions |
| 166 | + if callee_id in locations: |
| 167 | + # Inherit location info from callee |
| 168 | + callee_info = locations[callee_id] |
| 169 | + locations[loc_id] = { |
| 170 | + "file": callee_info["file"], |
| 171 | + "line": callee_info["line"], |
| 172 | + "column": callee_info["column"], |
| 173 | + "def_line": def_line, |
| 174 | + "is_callsite": True, |
| 175 | + "callsite_callee": callee_id, |
| 176 | + "callsite_caller": caller_id, |
| 177 | + } |
| 178 | + else: |
| 179 | + logger.warning( |
| 180 | + f"Callsite #loc{loc_id} references undefined callee #loc{callee_id}" |
| 181 | + ) |
| 182 | + # Note: We don't add this callsite to locations since callee is missing |
| 183 | + |
| 184 | + # Verify caller references (warning only, don't block) |
| 185 | + for loc_id, _callee_id, caller_id, _def_line in callsite_defs: |
| 186 | + if loc_id in locations and caller_id and caller_id not in locations: |
| 187 | + logger.warning( |
| 188 | + f"Callsite #loc{loc_id} references undefined caller #loc{caller_id}" |
| 189 | + ) |
| 190 | + |
| 191 | + # Attach definition line and alias metadata |
| 192 | + for k, v in def_line_map.items(): |
| 193 | + if k in locations: |
| 194 | + locations[k]["def_line"] = v |
| 195 | + for alias_id, target_id in alias_map.items(): |
144 | 196 | if alias_id in locations: |
145 | 197 | locations[alias_id]["alias_of"] = target_id |
146 | 198 | if alias_id in alias_name_map: |
|
0 commit comments