VIEW015: unused-custom-property
Custom property or view parameter is never read
| Code | VIEW015 |
| Name | unused-custom-property |
| Category | View structure (VIEW) |
| Default severity | warning |
| Enabled by default | yes |
| Fix available | sometimes |
| Fix safety | safe or unsafe, depending on the finding (see below) |
| ign-lint equivalent | UnusedCustomPropertiesRule |
What it does
Section titled “What it does”Reports custom properties (of the view and of its components) and view input parameters that nothing in the view reads.
A property counts as read when it is resolved by an exact reference, not by a text search:
{...}references in any expression of the view (expression bindings, expression transforms, expression-structure leaves, query parameters, tag expressions, map transforms), resolved against the component tree ({this.custom.x},{view.params.p},{../Card.custom.x},{/root/Card.custom.x});{view.custom}reads every view custom property;runScriptin an expression of the view runs its code withself,view,pageandsession: code that names any of them, or a computed script, counts as reading and writing every property of the view;- property binding paths and indirect tag binding references;
- scripts of the view (events, transforms, change scripts, message
handlers, custom methods, extension functions), parsed with the Jython
parser. The analysis is default-deny: a component, the view, a page or
session, a property container (
self.custom,self.view.params) or a local alias of one must be used in one of the enumerated forms (self.view.custom.x,self.custom['x'],self.custom.get('x'),'x' in self.custom,self.getSibling('A').custom.x,self.parent.getChild('A').custom.x,view = self.view, an argument of a library function, a custom method of the view, ...); any other use (passed to unknown code, iterated, stored, compared, formatted,self.custom.keysused without a call,self.custom[key], a script that does not parse) counts as reading and writing every property it could reach, so the rule stays silent rather than guess. The list of forms is indocs/internal/fix-safety.md; - builtins that read the caller's variables by name: a script that calls
locals(),vars(),dir(),evalorexecfile, runsexec, reaches frames (sys._getframe(),inspect.currentframe(),.f_locals) or reaches such a builtin in any other way (__builtin__.eval,from __builtin__ import locals as l,e = eval) reads everything. Every library name a script calls or uses as a value must be a plaindeffunction (or class, or literal constant), or not exist: a library variable or import may holdevalunder another name (ev = evalin a module,lib.util.ev('self.custom.x')reads the caller'sself); - project library functions a script passes
self, the view or a property container to (lib.util.handle(self),handle(view=self.view)): the function's body is followed with the same default-deny rules (param.view.custom.x,x = param.custom.yeven whenxis never used,param.getSibling('A').custom.y, passing it on to other library functions, up to 4 calls deep). A function that does not exist reads nothing (the call fails, whichREF002reports). A function that uses the value in a way that cannot be followed (it stores the value where it outlives the call, in aglobal, a module or class attribute, a default argument or a container it does not own, returns, yields or raises it, captures it in a nested function, or reaches stack frames withsys._getframe()orinspect), a function a child project overrides, a function that may be replaced at run time (its module runsexec,evalorexecfile, writesglobals()orsys.modules[__name__], sets itsfunc_code, or may overwrite it with a later definition orfrom x import *; a script assigns orsetattrs it; its module is used as a value, imported withimportlib.import_module, reached throughsys.modulesor code run from strings; a function or class of its module is used as a value anywhere (alias = handle,register(handle)) or itsfunc_globalsis reached), and calls of anything but a library function count as reading everything.
These never count as unused:
- properties with a binding or a change script (
propConfigbindingoronChange): the binding or script runs whether or not anything reads the value; outputparameters (whether they are written isVIEW019's concern);inoutparameters that the view writes;- names starting with
_, the convention for intentionally unused properties.
Input parameters set by an embedding view or a page URL are still reported: passing a value in does not make the view use it.
Why is this bad?
Section titled “Why is this bad?”Unused properties are dead configuration: readers have to work out that nothing depends on them, and unused parameters make callers pass values that are ignored.
Example
Section titled “Example”{"custom": {"unusedCounter": 0, "title": "Pumps"}, "root": {"type": "ia.display.label", "meta": {"name": "root"}, "propConfig": {"props.text": {"binding": {"type": "property", "config": {"path": "view.custom.title"}}}}}}unusedCounter is reported. Use instead: remove it.
For custom properties: removes the property and its propConfig
entries. Safe when nothing writes the property and the view's own
scripts prove it unread, without following values into library
functions. Unsafe when a script or a bidirectional binding writes it (the
write recreates the property, without the access and persistent
settings of its propConfig), when the finding relies on what a library
function does with a value of the view (code in other resources, which
other projects or run-time changes can invalidate), and for a view linted
outside its project whose scripts call names that may be library
functions. View parameters are never removed automatically (callers pass
them).
Like every fix, it is unsafe while code in the workspace may read the
files a fix edits (any file access, read, write, rename or delete, whose path
is not a literal outside the
workspace, or code that is not vetted); the project setting [fix] assume-scripts-do-not-read-workspace-files = true declares that no script
does (see docs/internal/fix-safety.md, "File reads").
ign-lint
Section titled “ign-lint”Equivalent of UnusedCustomPropertiesRule, with the same messages in
iglint ign-lint. ign-lint searches substrings, so view.custom.foo is
credited by {view.custom.foobar}, this.custom.x anywhere credits every
component's x, same-named components share one definition, and component
propConfig entries become bogus definitions (bugs 21 to 23). iglint
resolves every reference instead.
Generated from the rule metadata by iglint generate-docs; iglint rule VIEW015 prints the same page in the terminal. Source: docs/rules/VIEW015.md.