summaryrefslogtreecommitdiffstats
path: root/Tools/c-analyzer/c_symbols/resolve.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/c-analyzer/c_symbols/resolve.py')
-rw-r--r--Tools/c-analyzer/c_symbols/resolve.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/Tools/c-analyzer/c_symbols/resolve.py b/Tools/c-analyzer/c_symbols/resolve.py
new file mode 100644
index 0000000..dc876ae
--- /dev/null
+++ b/Tools/c-analyzer/c_symbols/resolve.py
@@ -0,0 +1,149 @@
+import os.path
+
+from c_analyzer_common import files
+from c_analyzer_common.info import UNKNOWN
+from c_parser import declarations, info
+from .info import Symbol
+from .source import _find_symbol
+
+
+# XXX need tests:
+# * look_up_known_symbol()
+# * symbol_from_source()
+# * get_resolver()
+# * symbols_to_variables()
+
+def look_up_known_symbol(symbol, knownvars, *,
+ match_files=(lambda f1, f2: f1 == f2),
+ ):
+ """Return the known variable matching the given symbol.
+
+ "knownvars" is a mapping of common.ID to parser.Variable.
+
+ "match_files" is used to verify if two filenames point to
+ the same file.
+ """
+ if not knownvars:
+ return None
+
+ if symbol.funcname == UNKNOWN:
+ if not symbol.filename or symbol.filename == UNKNOWN:
+ for varid in knownvars:
+ if not varid.funcname:
+ continue
+ if varid.name == symbol.name:
+ return knownvars[varid]
+ else:
+ return None
+ else:
+ for varid in knownvars:
+ if not varid.funcname:
+ continue
+ if not match_files(varid.filename, symbol.filename):
+ continue
+ if varid.name == symbol.name:
+ return knownvars[varid]
+ else:
+ return None
+ elif not symbol.filename or symbol.filename == UNKNOWN:
+ raise NotImplementedError
+ else:
+ return knownvars.get(symbol.id)
+
+
+def find_in_source(symbol, dirnames, *,
+ _perfilecache={},
+ _find_symbol=_find_symbol,
+ _iter_files=files.iter_files_by_suffix,
+ ):
+ """Return the Variable matching the given Symbol.
+
+ If there is no match then return None.
+ """
+ if symbol.filename and symbol.filename != UNKNOWN:
+ filenames = [symbol.filename]
+ else:
+ filenames = _iter_files(dirnames, ('.c', '.h'))
+
+ if symbol.funcname and symbol.funcname != UNKNOWN:
+ raise NotImplementedError
+
+ (filename, funcname, vartype
+ ) = _find_symbol(symbol.name, filenames, _perfilecache)
+ if filename == UNKNOWN:
+ return None
+ return info.Variable(
+ id=(filename, funcname, symbol.name),
+ vartype=vartype,
+ )
+
+
+def get_resolver(knownvars=None, dirnames=None, *,
+ _look_up_known=look_up_known_symbol,
+ _from_source=find_in_source,
+ ):
+ """Return a "resolver" func for the given known vars and dirnames.
+
+ The func takes a single Symbol and returns a corresponding Variable.
+ If the symbol was located then the variable will be valid, populated
+ with the corresponding information. Otherwise None is returned.
+ """
+ if knownvars:
+ knownvars = dict(knownvars) # a copy
+ def resolve_known(symbol):
+ found = _look_up_known(symbol, knownvars)
+ if found is None:
+ return None
+ elif symbol.funcname == UNKNOWN:
+ knownvars.pop(found.id)
+ elif not symbol.filename or symbol.filename == UNKNOWN:
+ knownvars.pop(found.id)
+ return found
+ if dirnames:
+ def resolve(symbol):
+ found = resolve_known(symbol)
+ if found is None:
+ return None
+ #return _from_source(symbol, dirnames)
+ else:
+ for dirname in dirnames:
+ if not dirname.endswith(os.path.sep):
+ dirname += os.path.sep
+ if found.filename.startswith(dirname):
+ break
+ else:
+ return None
+ return found
+ else:
+ resolve = resolve_known
+ elif dirnames:
+ def resolve(symbol):
+ return _from_source(symbol, dirnames)
+ else:
+ def resolve(symbol):
+ return None
+ return resolve
+
+
+def symbols_to_variables(symbols, *,
+ resolve=(lambda s: look_up_known_symbol(s, None)),
+ ):
+ """Yield the variable the matches each given symbol.
+
+ Use get_resolver() for a "resolve" func to use.
+ """
+ for symbol in symbols:
+ if isinstance(symbol, info.Variable):
+ # XXX validate?
+ yield symbol
+ continue
+ if symbol.kind != Symbol.KIND.VARIABLE:
+ continue
+ resolved = resolve(symbol)
+ if resolved is None:
+ #raise NotImplementedError(symbol)
+ resolved = info.Variable(
+ id=symbol.id,
+ vartype=UNKNOWN,
+ )
+ yield resolved