Prior to this patch, when comparing the paths of source files in Dexter commands, we would use os.samefile. This function performs actual file operations and requires the files to exist on the current system; this is suitable when running the test for the first time, but renders the DextIR output files non-portable, and unusable if the source files no longer exist in their original location. Differential Revision: https://reviews.llvm.org/D127099
119 lines
3.8 KiB
Python
119 lines
3.8 KiB
Python
# DExTer : Debugging Experience Tester
|
|
# ~~~~~~ ~ ~~ ~ ~~
|
|
#
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
"""Set of data classes for representing the complete debug program state at a
|
|
fixed point in execution.
|
|
"""
|
|
|
|
import os
|
|
|
|
from collections import OrderedDict
|
|
from pathlib import PurePath
|
|
from typing import List
|
|
|
|
class SourceLocation:
|
|
def __init__(self, path: str = None, lineno: int = None, column: int = None):
|
|
if path:
|
|
path = os.path.normcase(path)
|
|
self.path = path
|
|
self.lineno = lineno
|
|
self.column = column
|
|
|
|
def __str__(self):
|
|
return '{}({}:{})'.format(self.path, self.lineno, self.column)
|
|
|
|
def match(self, other) -> bool:
|
|
"""Returns true iff all the properties that appear in `self` have the
|
|
same value in `other`, but not necessarily vice versa.
|
|
"""
|
|
if not other or not isinstance(other, SourceLocation):
|
|
return False
|
|
|
|
if self.path and (other.path is None or (PurePath(self.path) != PurePath(other.path))):
|
|
return False
|
|
|
|
if self.lineno and (self.lineno != other.lineno):
|
|
return False
|
|
|
|
if self.column and (self.column != other.column):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
class StackFrame:
|
|
def __init__(self,
|
|
function: str = None,
|
|
is_inlined: bool = None,
|
|
location: SourceLocation = None,
|
|
watches: OrderedDict = None):
|
|
if watches is None:
|
|
watches = {}
|
|
|
|
self.function = function
|
|
self.is_inlined = is_inlined
|
|
self.location = location
|
|
self.watches = watches
|
|
|
|
def __str__(self):
|
|
return '{}{}: {} | {}'.format(
|
|
self.function,
|
|
' (inlined)' if self.is_inlined else '',
|
|
self.location,
|
|
{k: str(self.watches[k]) for k in self.watches})
|
|
|
|
def match(self, other) -> bool:
|
|
"""Returns true iff all the properties that appear in `self` have the
|
|
same value in `other`, but not necessarily vice versa.
|
|
"""
|
|
if not other or not isinstance(other, StackFrame):
|
|
return False
|
|
|
|
if self.location and not self.location.match(other.location):
|
|
return False
|
|
|
|
if self.watches:
|
|
for name in iter(self.watches):
|
|
try:
|
|
if isinstance(self.watches[name], dict):
|
|
for attr in iter(self.watches[name]):
|
|
if (getattr(other.watches[name], attr, None) !=
|
|
self.watches[name][attr]):
|
|
return False
|
|
else:
|
|
if other.watches[name].value != self.watches[name]:
|
|
return False
|
|
except KeyError:
|
|
return False
|
|
|
|
return True
|
|
|
|
class ProgramState:
|
|
def __init__(self, frames: List[StackFrame] = None):
|
|
self.frames = frames
|
|
|
|
def __str__(self):
|
|
return '\n'.join(map(
|
|
lambda enum: 'Frame {}: {}'.format(enum[0], enum[1]),
|
|
enumerate(self.frames)))
|
|
|
|
def match(self, other) -> bool:
|
|
"""Returns true iff all the properties that appear in `self` have the
|
|
same value in `other`, but not necessarily vice versa.
|
|
"""
|
|
if not other or not isinstance(other, ProgramState):
|
|
return False
|
|
|
|
if self.frames:
|
|
for idx, frame in enumerate(self.frames):
|
|
try:
|
|
if not frame.match(other.frames[idx]):
|
|
return False
|
|
except (IndexError, KeyError):
|
|
return False
|
|
|
|
return True
|