Feature/unused vars (#1)

* TypeChecker

- Adding new chapter `Variable referencing counting`

* TypeChecker

- Added missing method table
- Added code usage

* Markdown transform

- Updated

* Configuration

- Documented `typecheck:warnUnusedVars`

* Command line

- Added compiler flags documentation

* MK

- Built

* Command line

- Formatting fixed

* MK

- Built
This commit is contained in:
Tristan B. Velloza Kildaire 2023-11-05 17:25:05 +02:00 committed by GitHub
parent 99c10d4953
commit be9ed17d99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 5 deletions

View File

@ -207,3 +207,68 @@ This is a sanity check, as if the type coercion failed then an exception
would be thrown and the assertion would not be reached, however if the
types were an exact match **or** if they were not but could be coerced
as such then the two types should match.
### Variable referencing counting
Firstly let me make it clear that this has nothing to do with
**runtime** reference counting but rather a simple mechanism used to
maintain a count or *number of* references to variables after their
declaration.
Below is a method table of the methods of concern:
| Method | Description | Return |
|------------------------|-----------------------------------------------------------------------------------------------|--------------|
| `touch(Variable)` | Increments the count by 1 for the given variable, creates a mapping if one does not yet exist | `void` |
| `getUnusedVariables()` | Returns an array of all `Variable`s which have a reference count above `1` | `Variable[]` |
This aids us in implementing a single feature *unused variable
detection*. Its rather simple, reference counts are incremented by
using a `touch(Variable)` method defined in the `TypeChecker` and this
is called whilst doing dependency generation in the dependency
generator.
The first time a variable is encountered, such as even its declaration,
we will then `touch(...)`-it. At the end of type checking we then call
the `getUnusedVariables()` method which returns a list of the undeclared
variables. These are variables with a reference count higher than `1`.
We then print these out so the user can see which are unused.
#### Usage
Example usage below shows us `touch`-ing a variable when we process them
in expressions such as a `VariableExpression` in the dependency module:
``` d
...
/* Get the entity as a Variable */
Variable variable = cast(Variable)namedEntity;
/* Variable reference count must increase */
tc.touch(variable);
...
```
We then, after typechecking, run the following in the type checker
modules `doPostChecks()` method:
``` d
/**
* Find the variables which were declared but never used
*/
if(this.config.hasConfig("typecheck:warnUnusedVars") & this.config.getConfig("typecheck:warnUnusedVars").getBoolean())
{
Variable[] unusedVariables = getUnusedVariables();
gprintln("There are "~to!(string)(unusedVariables.length)~" unused variables");
if(unusedVariables.length)
{
foreach(Variable unusedVariable; unusedVariables)
{
// TODO: Get a nicer name, full path-based
gprintln("Variable '"~to!(string)(unusedVariable.getName())~"' is declared but never");
}
}
}
```

View File

@ -62,7 +62,7 @@ before adding them here
### Statements
Statements are inevitably the building blocks of a program and make use
of all the former defined sections of the grammar and more of themsleves
of all the former defined sections of the grammar and more of themselves
in some cases as well.
module ::= "module", ident, ";", {decl, ";"};

View File

@ -1,7 +1,7 @@
## Configuration
The T compiler can have various variables tweaked to control the
bahviour of the compiler
behavior of the compiler
### `types`
@ -9,10 +9,10 @@ Anything regarding the type system (this includes the type checker and
the meta processor).
1. `types:max_width`
- This entry holds an integrak value
- This entry holds an integral value
- This sets the maximum bit-width of a machine (in bytes)
- This can either be `1`, `2`, `4` or `8`
- It affects how alises such as `size_t` and `ssize_t` behave in
- It affects how aliases such as `size_t` and `ssize_t` behave in
terms of what the resolve to
### `dgen`
@ -57,3 +57,13 @@ This controls aspects of the `CodeEmitter` API, meaning irrespective of
which emitter (such as `dgen`) is used.
TODO: Move `dgen_emit_entrypoint_test` and `dgen:pretty_code` here.
### `typecheck`
This controls the aspects of the `TypeChecker`.
1. `typecheck:warnUnusedVars`
- If this is set to `true` then at the end of the typechecking
process a scan for all variables will be done and any variable
that is unused will be printed out
- Default: `true`

View File

@ -0,0 +1,12 @@
## Command-line
This documents the full set of available command-line flags one can use.
### `--unusedVars <boolean>`
- **What**: Allows one to toggle whether or not warnings about unused
variables should be printed out or not.
- **Where**: Can be used with the `typecheck`, `emit` and `compile`
commands.
- **How**: This toggles the compiler configuration entry
`typecheck:warnUnusedVars`

View File

@ -285,4 +285,56 @@ assert(isSameType(
); // Sanity check
```
This is a sanity check, as if the type coercion failed then an exception would be thrown and the assertion would not be reached, however if the types were an exact match **or** if they were not but could be coerced as such then the two types should match.
This is a sanity check, as if the type coercion failed then an exception would be thrown and the assertion would not be reached, however if the types were an exact match **or** if they were not but could be coerced as such then the two types should match.
### Variable referencing counting
Firstly let me make it clear that this has nothing to do with **runtime** reference counting but rather a simple mechanism used to maintain a count or _number of_ references to variables after their declaration.
Below is a method table of the methods of concern:
| Method | Description | Return |
|--------|-------------|--------|
| `touch(Variable)` | Increments the count by 1 for the given variable, creates a mapping if one does not yet exist | `void` |
| `getUnusedVariables()` | Returns an array of all `Variable`s which have a reference count above `1` | `Variable[]` |
This aids us in implementing a single feature _unused variable detection_. It's rather simple, reference counts are incremented by using a `touch(Variable)` method defined in the `TypeChecker` and this is called whilst doing dependency generation in the dependency generator.
The first time a variable is encountered, such as even its declaration, we will then `touch(...)`-it. At the end of type checking we then call the `getUnusedVariables()` method which returns a list of the undeclared variables. These are variables with a reference count higher than `1`. We then print these out so the user can see which are unused.
#### Usage
Example usage below shows us `touch`-ing a variable when we process them in expressions such as a `VariableExpression` in the dependency module:
```{.d .numberLines}
...
/* Get the entity as a Variable */
Variable variable = cast(Variable)namedEntity;
/* Variable reference count must increase */
tc.touch(variable);
...
```
We then, after typechecking, run the following in the type checker module's `doPostChecks()` method:
```{.d .numberLines}
/**
* Find the variables which were declared but never used
*/
if(this.config.hasConfig("typecheck:warnUnusedVars") & this.config.getConfig("typecheck:warnUnusedVars").getBoolean())
{
Variable[] unusedVariables = getUnusedVariables();
gprintln("There are "~to!(string)(unusedVariables.length)~" unused variables");
if(unusedVariables.length)
{
foreach(Variable unusedVariable; unusedVariables)
{
// TODO: Get a nicer name, full path-based
gprintln("Variable '"~to!(string)(unusedVariable.getName())~"' is declared but never");
}
}
}
```

View File

@ -47,3 +47,10 @@ This controls aspects of the `CodeEmitter` API, meaning irrespective of which em
TODO: Move `dgen_emit_entrypoint_test` and `dgen:pretty_code` here.
### `typecheck`
This controls the aspects of the `TypeChecker`.
1. `typecheck:warnUnusedVars`
* If this is set to `true` then at the end of the typechecking process a scan for all variables will be done and any variable that is unused will be printed out
* Default: `true`

View File

@ -0,0 +1,10 @@
## Command-line
This documents the full set of available command-line flags one can use.
### `--unusedVars <boolean>`
* **What**: Allows one to toggle whether or not warnings about unused variables should be printed out or not.
* **Where**: Can be used with the `typecheck`, `emit` and `compile` commands.
* **How**: This toggles the compiler configuration entry `typecheck:warnUnusedVars`