[dmd-internals] How not to report unused identifiers
cy via dmd-internals
dmd-internals at puremagic.com
Fri Apr 1 10:58:33 PDT 2016
On Wednesday, 30 March 2016 at 01:24:42 UTC, Jonathan M Davis
wrote:
> any attempt to warn about "unused identifiers" would have to
> be done very carefully.
Well, obviously that was a vague, ignorant first attempt. I do
realize some care would be needed. Though I don't think it's all
that difficult to define unused identifiers, finding them is a
lot more complicated than just listing the symbols a module has,
and subtracting the symbols it ends up exporting. I thought
search() would be called on internal symbols, not just exports.
> Aside from the normal issues with RAII and the like
So obviously any object with a constructor or a destructor would
have to be excluded. Something with pure versions of those should
probably be included though.
> it's _very_ common in D code to declare stuff and then not
> actually use it when dealing with template constraints and the
> traits tested in them,
I was sort of hoping to get in there after template instantiation
had been calculated and only ones with true constraints were left.
> templates and string mixins could run into trouble depending on
> the exact arguments used with them and how complicated some of
> their static if-else logic is.
Again, it's important not to check for unused identifiers until
you've given the programmer a chance to get rid of 'em
themselves. While it would be possible to check "if this
constraint had been true, THEN this code here with an unused
identifier would be used" I don't see any real utility to that. I
assume you're talking about like...
void main() {
int i = 42;
static if(false) {
int j = 23;
}
import std.stdio: writeln;
writeln(i);
}
I definitely would not include it as a goal to warn that "j"
would be an unused identifier, if you ever set the condition to
true. I'd be happy with a warning that only appeared when I did
set the condition to true, and angry with one that wouldn't go
away even if I used a CTFE to comment out the whole block of code
"#if 0" style.
It might be safe not to report any unused identifier that
appeared to be a type, not a variable or a module.
Anyway, if I could figure it out, this is what a "careful"
algorithm would do. First, it would only check after the module
has been fully instantiated, and all the compile time code has
been executed. Of all the symbols a module has, it removes the
ones that are touched by other modules (not just imported, but
actually used, by this algorithm recursively). Then it removes
any things that can have side effects even if not used, like
structs or classes with non-pure constructors/destructors.
Then, generally the only thing that crops up in heavily modified
code is unused imports, so there would be an option to report all
unused identifiers and if not, it would eliminate all remaining
symbols that weren't declared in a different module than this one.
Finally, it would have a set of unused identifiers. If the
aforementioned option were false, it'd build a set of statements
where those identifiers were imported, and highlight them giving
a warning about unused import. And if true, it'd report each
unused identifier, possibly grouped by the modules they came from.
Which is to say, that's what I would do, if I knew when to
instrument it post-CTFE but pre-runtime, if I knew how to check
if a symbol were an instantiation of an object with a
constructor/destructor, if I knew how to look up those functions,
if I knew how to check if a function is pure, if I knew how to
get the module a symbol was declared in, if I knew how to get the
statement a symbol was imported from, if I knew how to untangle
complicated templated types into the identifiers they're
constituted of, and if I knew how to add options to invoking dmd.
But for now, I'll have to use the strategy of repeatedly deleting
import statements, and recompiling to see if it breaks my code.
More information about the dmd-internals
mailing list