address review feedback form #94

This commit is contained in:
Jimmy Lai 2019-10-08 13:58:44 -07:00 committed by jimmylai
parent b690c591e5
commit 5f8f5c5624
3 changed files with 43 additions and 17 deletions

View file

@ -9,15 +9,13 @@
"==============\n",
"Scope Analysis\n",
"==============\n",
"Scope analysis keeps track of assignments and accesses which could be useful for code automatic refactoring. If you're not familiar with Scope analysis, see :doc:`Metadata <metadata>` for more detail about Scope metadata. This tutorial demonstrates some use cases of Scope analysis. \n",
"Given source codes, Scope analysis parses all variable :class:`~libcst.metadata.Assignment` (or a :class:`~libcst.metadata.BuiltinAssignment` if it's a builtin) and :class:`~libcst.metadata.Access` to store in :class:`~libcst.metadata.Scope` containers.\n",
"\n",
"Given the following example source code contains a couple of unused imports (``f``, ``i``, ``m`` and ``n``) and undefined variable references (``func_undefined`` and ``var_undefined``). Scope analysis helps us identifying those unused imports and undefined variables to automatically provide warnings to developers to prevent bugs while they're developing.\n",
"With a parsed :class:`~libcst.Module`, we construct a :class:`~libcst.metadata.MetadataWrapper` object and it provides a :func:`~libcst.metadata.MetadataWrapper.resolve` function to resolve metadata given a metadata provider.\n",
":class:`~libcst.metadata.ScopeProvider` is used here for analysing scope and there are three types of scopes (:class:`~libcst.metadata.GlobalScope`, :class:`~libcst.metadata.FunctionScope` and :class:`~libcst.metadata.ClassScope`) in this example.\n",
"Scope analysis keeps track of assignments and accesses which could be useful for code automatic refactoring. If you're not familiar with scope analysis, see :ref:`Scope Metadata <libcst-scope-metadata>` for more detail about scope metadata. This tutorial demonstrates some use cases of scope analysis. If you're new to metadata, see :doc:`Metadata Tutorial <metadata_tutorial>` to get started.\n",
"Given source codes, scope analysis parses all variable :class:`~libcst.metadata.Assignment` (or a :class:`~libcst.metadata.BuiltinAssignment` if it's a builtin) and :class:`~libcst.metadata.Access` to store in :class:`~libcst.metadata.Scope` containers.\n",
"\n",
".. note::\n",
" The scope analysis only handles local variable name access and cannot handle simple string type annotation forward references. See :class:`~libcst.metadata.Access`\n"
" The scope analysis only handles local variable name access and cannot handle simple string type annotation forward references. See :class:`~libcst.metadata.Access`\n",
"\n",
"Given the following example source code contains a couple of unused imports (``f``, ``i``, ``m`` and ``n``) and undefined variable references (``func_undefined`` and ``var_undefined``). Scope analysis helps us identifying those unused imports and undefined variables to automatically provide warnings to developers to prevent bugs while they're developing.\n"
]
},
{
@ -38,8 +36,6 @@
"metadata": {},
"outputs": [],
"source": [
"import libcst as cst\n",
"\n",
"source = \"\"\"\\\n",
"import a, b, c as d, e as f # expect to keep: a, c as d\n",
"from g import h, i, j as k, l as m # expect to keep: h, j as k\n",
@ -56,7 +52,28 @@
" def __new__(self) -> \"Cls\":\n",
" var = k.method()\n",
" func_undefined(var_undefined)\n",
"\"\"\"\n",
"\"\"\""
]
},
{
"cell_type": "raw",
"metadata": {
"raw_mimetype": "text/restructuredtext"
},
"source": [
"With a parsed :class:`~libcst.Module`, we construct a :class:`~libcst.metadata.MetadataWrapper` object and it provides a :func:`~libcst.metadata.MetadataWrapper.resolve` function to resolve metadata given a metadata provider.\n",
":class:`~libcst.metadata.ScopeProvider` is used here for analysing scope and there are three types of scopes (:class:`~libcst.metadata.GlobalScope`, :class:`~libcst.metadata.FunctionScope` and :class:`~libcst.metadata.ClassScope`) in this example.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import libcst as cst\n",
"\n",
"\n",
"wrapper = cst.metadata.MetadataWrapper(cst.parse_module(source))\n",
"scopes = set(wrapper.resolve(cst.metadata.ScopeProvider).values())\n",
"for scope in scopes:\n",
@ -176,7 +193,7 @@
"raw_mimetype": "text/restructuredtext"
},
"source": [
"After the transform, we use ``.code`` to generate fixed code and all unused names are fixed as expected!"
"After the transform, we use ``.code`` to generate fixed code and all unused names are fixed as expected! The difflib is used to show only changed part and only import lines are updated as expected."
]
},
{
@ -185,8 +202,15 @@
"metadata": {},
"outputs": [],
"source": [
"import difflib\n",
"fixed_module = wrapper.module.visit(RemoveUnusedImportTransformer(unused_imports))\n",
"print(fixed_module.code)"
"\n",
"# Use difflib to show the changes to verify unused imports are removed as expected.\n",
"print(\n",
" \"\".join(\n",
" difflib.unified_diff(source.splitlines(1), fixed_module.code.splitlines(1))\n",
" )\n",
")"
]
}
],