bpo-36876: Re-organize the c-analyzer tool code. (gh-16841)
This is partly a cleanup of the code. It also is preparation for getting the variables from the source (cross-platform) rather than from the symbols.
The change only touches the tool (and its tests).
diff --git a/Tools/c-analyzer/cpython/find.py b/Tools/c-analyzer/cpython/find.py
new file mode 100644
index 0000000..a7bc0b4
--- /dev/null
+++ b/Tools/c-analyzer/cpython/find.py
@@ -0,0 +1,101 @@
+import os.path
+
+from c_analyzer.common import files
+from c_analyzer.common.info import UNKNOWN, ID
+from c_analyzer.variables import find as _common
+
+from . import SOURCE_DIRS, PYTHON, REPO_ROOT
+from .known import (
+ from_file as known_from_file,
+ DATA_FILE as KNOWN_FILE,
+ )
+from .supported import (
+ ignored_from_file, IGNORED_FILE, is_supported, _is_object,
+ )
+
+# XXX need tests:
+# * vars_from_binary()
+# * vars_from_source()
+# * supported_vars()
+
+
+def _handle_id(filename, funcname, name, *,
+ _relpath=os.path.relpath,
+ ):
+ filename = _relpath(filename, REPO_ROOT)
+ return ID(filename, funcname, name)
+
+
+def vars_from_binary(*,
+ known=KNOWN_FILE,
+ _known_from_file=known_from_file,
+ _iter_files=files.iter_files_by_suffix,
+ _iter_vars=_common.vars_from_binary,
+ ):
+ """Yield a Variable for each found Symbol.
+
+ Details are filled in from the given "known" variables and types.
+ """
+ if isinstance(known, str):
+ known = _known_from_file(known)
+ dirnames = SOURCE_DIRS
+ suffixes = ('.c',)
+ filenames = _iter_files(dirnames, suffixes)
+ # XXX For now we only use known variables (no source lookup).
+ filenames = None
+ yield from _iter_vars(PYTHON,
+ known=known,
+ filenames=filenames,
+ handle_id=_handle_id,
+ check_filename=(lambda n: True),
+ )
+
+
+def vars_from_source(*,
+ preprocessed=None,
+ known=KNOWN_FILE,
+ _known_from_file=known_from_file,
+ _iter_files=files.iter_files_by_suffix,
+ _iter_vars=_common.vars_from_source,
+ ):
+ """Yield a Variable for each declaration in the raw source code.
+
+ Details are filled in from the given "known" variables and types.
+ """
+ if isinstance(known, str):
+ known = _known_from_file(known)
+ dirnames = SOURCE_DIRS
+ suffixes = ('.c',)
+ filenames = _iter_files(dirnames, suffixes)
+ yield from _iter_vars(filenames,
+ preprocessed=preprocessed,
+ known=known,
+ handle_id=_handle_id,
+ )
+
+
+def supported_vars(*,
+ known=KNOWN_FILE,
+ ignored=IGNORED_FILE,
+ skip_objects=False,
+ _known_from_file=known_from_file,
+ _ignored_from_file=ignored_from_file,
+ _iter_vars=vars_from_binary,
+ _is_supported=is_supported,
+ ):
+ """Yield (var, is supported) for each found variable."""
+ if isinstance(known, str):
+ known = _known_from_file(known)
+ if isinstance(ignored, str):
+ ignored = _ignored_from_file(ignored)
+
+ for var in _iter_vars(known=known):
+ if not var.isglobal:
+ continue
+ elif var.vartype == UNKNOWN:
+ yield var, None
+ # XXX Support proper filters instead.
+ elif skip_objects and _is_object(found.vartype):
+ continue
+ else:
+ yield var, _is_supported(var, ignored, known)