-
Notifications
You must be signed in to change notification settings - Fork 13
Linter
This document was generated from 'src/documentation/wiki-linter.ts' on 2026-07-25, 12:45:26 UTC presenting an overview of flowR's linter (v2.13.2, using R v4.6.1). Please do not edit this file/wiki page directly. This page describes the flowR linter, which is a tool that utilizes flowR's dataflow analysis to find common issues in R scripts. The linter can currently be used through the linter query. Some rules also draw on the signature database. For example:
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
flowR repl v2.13.2, R grammar v14 (tree-sitter engine)
R> :query @linter "read.csv(\"/root/x.txt\")"Output
Query: linter (14 ms)
╰ Deprecated Functions (deprecated-functions): no findings
╰ File Path Validity (file-path-validity):
╰ certain:
╰ Path `/root/x.txt` at 1.1-23
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 5, processTimeMs: 0
╰ Seeded Randomness (seeded-randomness): no findings
╰ Absolute Paths (absolute-file-paths):
╰ certain:
╰ Path `/root/x.txt` at 1.1-23
╰ Metadata: totalConsidered: 1, totalUnknown: 0, searchTimeMs: 0, processTimeMs: 0
╰ Unused Definitions (unused-definitions): no findings
╰ Network Functions (network-functions): no findings
╰ Dataframe Access Validation (dataframe-access-validation): no findings
╰ Dead Code (dead-code): no findings
╰ Useless Loops (useless-loop): no findings
╰ Problematic inputs (problematic-inputs): no findings
╰ Stop without call.=False argument (stop-call): no findings
╰ Roxygen Arguments (roxygen-arguments): no findings
╰ No Leaked Credentials (no-leaked-credentials): no findings
╰ Undefined Symbol (undefined-symbol): no findings
All queries together required ≈14 ms (1ms accuracy, total 14 ms)
The linter will analyze the code and return any issues found. Formatted more nicely, this returns:
[ { "type": "linter" } ](This can be shortened to @linter when used with the REPL command :query).
Results (prettified and summarized):
Query: linter (14 ms)
╰ Deprecated Functions (deprecated-functions): no findings
╰ File Path Validity (file-path-validity):
╰ certain:
╰ Path /root/x.txt at 1.1-23
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 1, processTimeMs: 0
╰ Seeded Randomness (seeded-randomness): no findings
╰ Absolute Paths (absolute-file-paths):
╰ certain:
╰ Path /root/x.txt at 1.1-23
╰ Metadata: totalConsidered: 1, totalUnknown: 0, searchTimeMs: 1, processTimeMs: 0
╰ Unused Definitions (unused-definitions): no findings
╰ Network Functions (network-functions): no findings
╰ Dataframe Access Validation (dataframe-access-validation): no findings
╰ Dead Code (dead-code): no findings
╰ Useless Loops (useless-loop): no findings
╰ Problematic inputs (problematic-inputs): no findings
╰ Stop without call.=False argument (stop-call): no findings
╰ Roxygen Arguments (roxygen-arguments): no findings
╰ No Leaked Credentials (no-leaked-credentials): no findings
╰ Undefined Symbol (undefined-symbol): no findings
All queries together required ≈14 ms (1ms accuracy, total 15 ms)
Show Detailed Results as Json
The analysis required 14.8 ms (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR. Please consult the Interface wiki page for more information on how to get those.
{
"linter": {
"results": {
"deprecated-functions": {
"results": [],
".meta": {
"totalCalls": 0,
"totalFunctionDefinitions": 0,
"searchTimeMs": 3,
"processTimeMs": 3
}
},
"file-path-validity": {
"results": [
{
"involvedId": 3,
"loc": [
1,
1,
1,
23
],
"filePath": "/root/x.txt",
"certainty": "certain"
}
],
".meta": {
"totalReads": 1,
"totalUnknown": 0,
"totalWritesBeforeAlways": 0,
"totalValid": 0,
"searchTimeMs": 1,
"processTimeMs": 0
}
},
"seeded-randomness": {
"results": [],
".meta": {
"consumerCalls": 0,
"callsWithFunctionProducers": 0,
"callsWithAssignmentProducers": 0,
"callsWithNonConstantProducers": 0,
"callsWithOtherBranchProducers": 0,
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"absolute-file-paths": {
"results": [
{
"certainty": "certain",
"filePath": "/root/x.txt",
"loc": [
1,
1,
1,
23
]
}
],
".meta": {
"totalConsidered": 1,
"totalUnknown": 0,
"searchTimeMs": 1,
"processTimeMs": 0
}
},
"unused-definitions": {
"results": [],
".meta": {
"totalConsidered": 0,
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"network-functions": {
"results": [],
".meta": {
"totalCalls": 0,
"totalFunctionDefinitions": 0,
"searchTimeMs": 1,
"processTimeMs": 0
}
},
"dataframe-access-validation": {
"results": [],
".meta": {
"numOperations": 0,
"numAccesses": 0,
"totalAccessed": 0,
"searchTimeMs": 0,
"processTimeMs": 1
}
},
"dead-code": {
"results": [],
".meta": {
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"useless-loop": {
"results": [],
".meta": {
"numOfUselessLoops": 0,
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"problematic-inputs": {
"results": [],
".meta": {
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"stop-call": {
"results": [],
".meta": {
"consideredNodes": 0,
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"roxygen-arguments": {
"results": [],
".meta": {
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"no-leaked-credentials": {
"results": [],
".meta": {
"totalChecked": 0,
"searchTimeMs": 0,
"processTimeMs": 0
}
},
"undefined-symbol": {
"results": [],
".meta": {
"totalFunctionCalls": 1,
"totalVariableUses": 0,
"suppressed": {
"installed": 0,
"loadedPackage": 0,
"enclosingScope": 0,
"nonStandardEval": 0,
"subscript": 0
},
"searchTimeMs": 0,
"processTimeMs": 3
}
}
},
".meta": {
"timing": 14
}
},
".meta": {
"timing": 14
}
}Note
If you want to add a new linting rule, see Create Linting Rules.
The following linting rules are available:
Absolute Paths: Checks whether file paths are absolute. [see src/linter/rules/absolute-path.ts]
Dataframe Access Validation: Validates the existence of accessed columns and rows of dataframes. [see src/linter/rules/dataframe-access-validation.ts]
Dead Code: Marks areas of code that are never reached during execution. [see src/linter/rules/dead-code.ts]
Deprecated Functions: Marks deprecated functions that should not be used anymore. [see src/linter/rules/deprecated-functions.ts]
File Path Validity: Checks whether file paths used in read and write operations are valid and point to existing files. [see src/linter/rules/file-path-validity.ts]
Naming Convention: Checks whether the symbols conform to a certain naming convention [see src/linter/rules/naming-convention.ts]
Network Functions: Marks network functions that execute network operations, such as downloading files or making HTTP requests. [see src/linter/rules/network-functions.ts]
No Leaked Credentials: Detects hardcoded credentials assigned to variables whose names suggest they hold passwords, tokens, or API keys, or whose values match known credential formats (AWS, GitHub, Slack, Stripe, SSH). [see src/linter/rules/no-leaked-credentials.ts]
Problematic inputs: Detects uses of dynamic calls (e.g. eval, system) with non-constant inputs, and graphics-device calls (pdf, postscript) where a filename starts with '|' indicating a pipe command injection. [see src/linter/rules/problematic-inputs.ts]
Roxygen Arguments: Checks whether a function has undocumented or overdocumented parameters [see src/linter/rules/roxygen-arguments.ts]
Seeded Randomness: Checks whether randomness-based function calls are preceded by a random seed generation function. For consistent reproducibility, functions that use randomness should only be called after a constant random seed is set using a function like set.seed. [see src/linter/rules/seeded-randomness.ts]
Software Has License: Checks whether the software project provides a license (via a LICENSE file or the DESCRIPTION file License field). [see src/linter/rules/software-has-license.ts]
Software Has Tests: Checks whether the software project has tests (test files in a test directory or test function calls in R code). [see src/linter/rules/software-has-tests.ts]
Stop without call.=False argument: Checks whether stop calls without call. argument set to FALSE are used. [see src/linter/rules/stop-with-call-arg.ts]
Syntactically Valid: Checks whether the code is free of syntax errors, using the configured (error-tolerant) parser, and offers extensible quick-fixes to repair them. [see src/linter/rules/syntactically-valid.ts]
Undefined Symbol: Flags functions and variables that are neither defined locally, a base R builtin, nor exported by a loaded package. [see src/linter/rules/undefined-symbol.ts]
Unused Definitions: Checks for unused definitions. [see src/linter/rules/unused-definition.ts]
Useless Loops: Detect loops which only iterate once [see src/linter/rules/useless-loop.ts]
We use tags to categorize linting rules for users. The following tags are available:
| Tag/Badge | Description |
|---|---|
|
|
This rule is used to detect bugs in the code. Everything that affects the semantics of the code, such as incorrect function calls, wrong arguments, etc. is to be considered a bug. Otherwise, it may be a smell or a style issue. (rules: file-path-validity, dataframe-access-validation, undefined-symbol, and syntactically-valid) |
|
|
This signals the use of deprecated functions or features. (rule: deprecated-functions) |
|
|
This rule is used to detect issues that are related to the documentation of the code. For example, missing or misleading comments. (rules: roxygen-arguments and software-has-license) |
|
|
This marks rules which are currently considered experimental, not that they detect experimental code. (rules: no-leaked-credentials and undefined-symbol) |
|
|
This rule is used to detect issues that are related to the performance of the code. For example, inefficient algorithms, unnecessary computations, or unoptimized data structures. (rules: network-functions and problematic-inputs) |
|
|
This rule is used to detect issues that are related to the portability of the code. For example, platform-specific code, or code that relies on specific R versions or packages. (rules: file-path-validity, seeded-randomness, absolute-file-paths, and syntactically-valid) |
|
|
The rule is specific to R version 3.x. (rules: none) |
|
|
The rule is specific to R version 4.x. (rules: none) |
|
|
This rule is used to detect issues that are related to the readability of the code. For example, complex expressions, long lines, or inconsistent formatting. (rules: unused-definitions, useless-loop, and problematic-inputs) |
|
|
This rule is used to detect issues that are related to the reproducibility of the code. For example, missing or incorrect random seeds, or missing data. (rules: deprecated-functions, file-path-validity, seeded-randomness, absolute-file-paths, network-functions, dataframe-access-validation, dead-code, and software-has-tests) |
|
|
This rule is used to detect security-critical. For example, missing input validation. (rules: network-functions, problematic-inputs, and no-leaked-credentials) |
|
|
This rule is used to detect issues that are related to the shiny framework. (rules: none) |
|
|
This rule is used to detect issues that do not directly affect the semantics of the code, but are still considered bad practice. (rules: deprecated-functions, absolute-file-paths, unused-definitions, network-functions, dead-code, useless-loop, problematic-inputs, stop-call, roxygen-arguments, and no-leaked-credentials) |
|
|
This rule is used to detect issues that are related to the style of the code. For example, inconsistent naming conventions, or missing or incorrect formatting. (rules: naming-convention and roxygen-arguments) |
|
|
This rule is used to detect issues that are related to the (re-)usability of the code. For example, missing or incorrect error handling, or missing or incorrect user interface elements. (rules: deprecated-functions, dataframe-access-validation, dead-code, software-has-license, and software-has-tests) |
|
|
This rule may provide quickfixes to automatically fix the issues it detects. (rules: file-path-validity, absolute-file-paths, unused-definitions, naming-convention, and syntactically-valid) |
Both linting rules and their individual results are additionally categorized by how certain the linter is that the results it is returning are valid.
| Rule Certainty | Description |
|---|---|
exact
|
Linting rules that are expected to have both high precision and high recall. (rules: none) |
best-effort
|
Linting rules that are expected to have high precision, but not necessarily high recall. Rules with this certainty generally ensure that the results they return are correct, but may not return all results. (rules: deprecated-functions, file-path-validity, seeded-randomness, absolute-file-paths, unused-definitions, network-functions, dataframe-access-validation, dead-code, useless-loop, problematic-inputs, stop-call, roxygen-arguments, software-has-license, software-has-tests, no-leaked-credentials, and syntactically-valid) |
over-approximative
|
Linting rules that are expected to have high recall, but not necessarily high precision. Rules with this certainty generally return all relevant results, but may also include some incorrect matches. (rules: naming-convention and undefined-symbol) |
Currently maintained by Florian Sihler and Oliver Gerstl at Ulm University
Email | GitHub | Penguins | Portfolio
- 🧑💻 Developer Onboarding
- 💻 Setup
- 👓 Overview
- 🪟 Interfacing with flowR
- 🌋 Core
- 🧹 Testing & Linting (Benchmark Page)
⁉️ FAQ- ℹ️ Extra Information