mirror of https://github.com/tbklang/tlang.git
Merge branch 'vardec_varass_dependency' into feature/multi_module
This commit is contained in:
commit
0a3a543f98
|
@ -382,6 +382,11 @@ jobs:
|
|||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Unused variables check (positive case)
|
||||
run: ./tlang typecheck source/tlang/testing/unused_vars.t --unusedVars true
|
||||
- name: Unused variables check (negative case)
|
||||
run: ./tlang typecheck source/tlang/testing/unused_vars_none.t --unusedVars true
|
||||
|
||||
emit:
|
||||
needs: [build, unittests]
|
||||
|
|
|
@ -129,7 +129,15 @@ mixin template EmitBase()
|
|||
*/
|
||||
mixin template TypeCheckerBase()
|
||||
{
|
||||
@ArgNamed("unusedVars|uvars", "Warn about any unused variables")
|
||||
@(ArgConfig.optional)
|
||||
bool warnUnusedVariables = true;
|
||||
|
||||
void TypeCheckerInit(Compiler compiler)
|
||||
{
|
||||
// Set whether to warn about unused variables
|
||||
compiler.getConfig().addConfig(ConfigEntry("typecheck:warnUnusedVars", warnUnusedVariables));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,6 +173,9 @@ struct compileCommand
|
|||
/* Setup general configuration parameters */
|
||||
BaseCommandInit(compiler);
|
||||
|
||||
/* Setup all type checker related parameters */
|
||||
TypeCheckerInit(compiler);
|
||||
|
||||
/* Perform tokenization */
|
||||
compiler.doLex();
|
||||
writeln("=== Tokens ===\n");
|
||||
|
@ -331,6 +342,9 @@ struct typecheckCommand
|
|||
/* Setup general configuration parameters */
|
||||
BaseCommandInit(compiler);
|
||||
|
||||
/* Setup all type checker related parameters */
|
||||
TypeCheckerInit(compiler);
|
||||
|
||||
compiler.doLex();
|
||||
writeln("=== Tokens ===\n");
|
||||
writeln(compiler.getTokens());
|
||||
|
|
|
@ -246,6 +246,9 @@ public final class CompilerConfiguration
|
|||
// FIXME: Make true by default - this WILL break many unittests and semantic ones
|
||||
// so be very sure before you enable this
|
||||
config.addConfig(ConfigEntry("modman:strict_headers", false));
|
||||
|
||||
/* Always warn about unused variables */
|
||||
config.addConfig(ConfigEntry("typecheck:warnUnusedVars", true));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -246,9 +246,22 @@ public class Compiler
|
|||
this.typeChecker.beginCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type checker instance of
|
||||
* this compiler
|
||||
*
|
||||
* Returns: the type checker
|
||||
* Throws:
|
||||
* CompilerException if you have not
|
||||
* called `doTypeCheck()` yet
|
||||
*/
|
||||
public TypeChecker getTypeChecker()
|
||||
{
|
||||
// TODO: Should we do a check for if `doTypeCheck()` was called or not?
|
||||
if(typeChecker is null)
|
||||
{
|
||||
throw new CompilerException(CompilerError.TYPECHECK_NOT_YET_PERFORMED);
|
||||
}
|
||||
|
||||
return this.typeChecker;
|
||||
}
|
||||
|
||||
|
|
|
@ -242,6 +242,34 @@ public final class TypeChecker
|
|||
*/
|
||||
initsScratchToModQueue(mod);
|
||||
}
|
||||
|
||||
/* Collect statistics */
|
||||
doPostChecks();
|
||||
}
|
||||
|
||||
/**
|
||||
* These are just checks we run for the convenience
|
||||
* of the user. They do not manipulate anything but
|
||||
* rather provide statistics
|
||||
*/
|
||||
private void doPostChecks()
|
||||
{
|
||||
/**
|
||||
* 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 used");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3458,6 +3486,51 @@ public final class TypeChecker
|
|||
//assert()
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a given `Variable` to its reference
|
||||
* count. This includes the declaration
|
||||
* thereof.
|
||||
*/
|
||||
private uint[Variable] varRefCounts;
|
||||
|
||||
/**
|
||||
* Increments the given variable's reference
|
||||
* count
|
||||
*
|
||||
* Params:
|
||||
* variable = the variable
|
||||
*/
|
||||
void touch(Variable variable)
|
||||
{
|
||||
// Create entry if not existing yet
|
||||
if(variable !in this.varRefCounts)
|
||||
{
|
||||
this.varRefCounts[variable] = 0;
|
||||
}
|
||||
|
||||
// Increment count
|
||||
this.varRefCounts[variable]++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all variables which were declared
|
||||
* but not used
|
||||
*
|
||||
* Returns: the array of variables
|
||||
*/
|
||||
public Variable[] getUnusedVariables()
|
||||
{
|
||||
Variable[] unused;
|
||||
foreach(Variable variable; this.varRefCounts.keys())
|
||||
{
|
||||
if(!(this.varRefCounts[variable] > 1))
|
||||
{
|
||||
unused ~= variable;
|
||||
}
|
||||
}
|
||||
|
||||
return unused;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -3796,4 +3869,64 @@ unittest
|
|||
compiler.doTypeCheck();
|
||||
|
||||
/* TODO: Actually test generated code queue */
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the unused variable detection mechanism
|
||||
*
|
||||
* Case: Positive (unused variables exist)
|
||||
* Source file: source/tlang/testing/unused_vars.t
|
||||
*/
|
||||
unittest
|
||||
{
|
||||
// Dummy field out
|
||||
File fileOutDummy;
|
||||
import tlang.compiler.core;
|
||||
|
||||
string sourceFile = "source/tlang/testing/unused_vars.t";
|
||||
|
||||
|
||||
Compiler compiler = new Compiler(gibFileData(sourceFile), fileOutDummy);
|
||||
compiler.doLex();
|
||||
compiler.doParse();
|
||||
compiler.doTypeCheck();
|
||||
TypeChecker tc = compiler.getTypeChecker();
|
||||
|
||||
/**
|
||||
* There should be 1 unused variable and then
|
||||
* it should be named `j`
|
||||
*/
|
||||
Variable[] unusedVars = tc.getUnusedVariables();
|
||||
assert(unusedVars.length == 1);
|
||||
Variable unusedVarActual = unusedVars[0];
|
||||
Variable unusedVarExpected = cast(Variable)tc.getResolver().resolveBest(tc.getModule(), "j");
|
||||
assert(unusedVarActual is unusedVarExpected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the unused variable detection mechanism
|
||||
*
|
||||
* Case: Negative (unused variables do NOT exist)
|
||||
* Source file: source/tlang/testing/unused_vars_none.t
|
||||
*/
|
||||
unittest
|
||||
{
|
||||
// Dummy field out
|
||||
File fileOutDummy;
|
||||
import tlang.compiler.core;
|
||||
|
||||
string sourceFile = "source/tlang/testing/unused_vars_none.t";
|
||||
|
||||
|
||||
Compiler compiler = new Compiler(gibFileData(sourceFile), fileOutDummy);
|
||||
compiler.doLex();
|
||||
compiler.doParse();
|
||||
compiler.doTypeCheck();
|
||||
TypeChecker tc = compiler.getTypeChecker();
|
||||
|
||||
/**
|
||||
* There should be 0 unused variables
|
||||
*/
|
||||
Variable[] unusedVars = tc.getUnusedVariables();
|
||||
assert(unusedVars.length == 0);
|
||||
}
|
|
@ -734,6 +734,9 @@ public class DNodeGenerator
|
|||
/* Get the entity as a Variable */
|
||||
Variable variable = cast(Variable)namedEntity;
|
||||
|
||||
/* Variable reference count must increase */
|
||||
tc.touch(variable);
|
||||
|
||||
/* Pool the node */
|
||||
VariableNode varDecNode = poolT!(VariableNode, Variable)(variable);
|
||||
|
||||
|
@ -1041,6 +1044,9 @@ public class DNodeGenerator
|
|||
writeln("Hello");
|
||||
writeln("VarType: "~to!(string)(variableType));
|
||||
|
||||
/* Add an entry to the reference counting map */
|
||||
tc.touch(variable);
|
||||
|
||||
/* Basic type */
|
||||
if(cast(Primitive)variableType)
|
||||
{
|
||||
|
@ -1143,6 +1149,9 @@ public class DNodeGenerator
|
|||
Variable variable = cast(Variable)tc.getResolver().resolveBest(c, vAsStdAl.getVariableName());
|
||||
assert(variable);
|
||||
|
||||
/* Assinging to a variable is usage, therefore increment the reference count */
|
||||
tc.touch(variable);
|
||||
|
||||
|
||||
/* Pool the variable */
|
||||
DNode varDecDNode = pool(variable);
|
||||
|
@ -1620,5 +1629,4 @@ public class DNodeGenerator
|
|||
|
||||
return classDNode;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module unused_vars;
|
||||
|
||||
int j;
|
|
@ -0,0 +1,8 @@
|
|||
module unused_vars;
|
||||
|
||||
int j;
|
||||
|
||||
void thing()
|
||||
{
|
||||
j = 1;
|
||||
}
|
Loading…
Reference in New Issue