New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate unused variable warnings in top level statements #7023
Conversation
@swift-ci Please test |
Nice! |
Build failed |
@@ -731,6 +732,7 @@ void swift::performWholeModuleTypeChecking(SourceFile &SF) { | |||
Ctx.diagnoseObjCMethodConflicts(SF); | |||
Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF); | |||
Ctx.diagnoseUnintendedObjCMethodOverrides(SF); | |||
performTopLevelDeclDiagnostics(SF); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section is only for diagnostics that apply across files. performTopLevelDeclDiagnostics
is something we can just do in the regular performTypeChecking
, and ideally only on the newly-added decls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I actually only put it there because I was originally exploring cross-file global variable checking, which turned out to be more complicated. I logged SR-3721 to track that. I'll move this to a better place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the invocation but I'm not sure I followed the ideally only on the newly-added decls
comment.
@@ -691,6 +692,7 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, | |||
TC.processREPLTopLevel(SF, TLC, StartElem); | |||
|
|||
typeCheckFunctionsAndExternalDecls(TC); | |||
performTopLevelDeclDiagnostics(SF); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…and now that I look at it a second time, does it make sense to sink it into typeCheckTopLevelCodeDecl? That way we don't have to walk things twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This also un-covered a lot of masked warnings since I shared the VarDeclUsageChecker
across multiple statements. This produced a bunch of new UT failures that I fixed and also un-covered a bug when guard
adds a variable to the global scope.
@swift-ci Please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see the problem. We would need the same VarDeclUsageChecker to walk all of the TLCDs in order to track usage of local variables. Okay, sorry for the bad advice; I think it was better as a full pass where you can catch guard let
as well.
D->walk(checker); | ||
} | ||
void swift:: | ||
performTopLevelDeclDiagnostics(TypeChecker &TC, TopLevelCodeDecl &TLCD) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For whatever reason, we don't really pass AST nodes as references, just pointers. Please use that convention for now.
@@ -1585,4 +1585,6 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { | |||
StmtChecker(*this, TLCD).typeCheckStmt(Body); | |||
TLCD->setBody(Body); | |||
checkTopLevelErrorHandling(TLCD); | |||
if (TLCD) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since TLCD
is dereferenced two lines above, it should be okay to drop this check.
Nope, the advice was good, and good to know about the conventions. I logged SR-3721 for unused global variable warnings since I think that would still be a valuable feature, especially for scripting. |
Yeah, unused (and only-written) variables are good things to catch. Do you disagree with my comment about |
I don't think we can do a better job with guard statements under a TLCD. Since they introduce global variables, and global variables can't be effectively tracked without more work. I'm interested expanding the checker to work better as scopes change, but would need some help making sure I have a good strategy, because the walking strategy would need to be changed substantially. I'll add some more notes on issues I've seen in the checker to SR-3721. |
}); | ||
} | ||
} | ||
else if (node.is<Stmt *>()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: } else if
. (no new-line after }
)
@KingOfBrian The new ASTScope stuff being worked on by @DougGregor might help with modeling bindings introduced by guard statements... |
Ah, guard statements do not introduce global variables. You can see this in the AST dump: let x = 5
guard let y = x as Optional else { fatalError() }
Note the VarDecl for @slavapestov: I don't think we can count on getting ASTScope any time soon. |
P.S. |
Deliberately so. It never makes sense to access a |
Oh neat, I actually didn't realize file scope was possible without access control modifiers. Still the VarDeclUsageChecker doesn't work well scoping variables through TypeDecl's or AbstractFuncDecls. Currently an inner function squashes the checker since the func decl is not type checked when the checker runs. ie:
It also doesn't traverse types at all so the following also won't be detected:
The above isn't an issue currently, since the checker never runs on variables that a type can close over. So I'm not sure how much better this can get without a new abstraction, and it sounds like one is planned. If you think this fix should get punted till that abstraction is in place, that's cool by me. I learned a lot about how the driver worked and got somewhat comfortable with my first |
Heh, that latter code snippet actually crashes if you get to SILGen. Arguably you shouldn't be allowed to do that; as before, the class might be referenced from another file. You've convinced me that this is a reasonable limitation for now. |
@swift-ci Please smoke test |
Also, to be less defeatist about this, we could invoke this checker a bit later in the type check phase. If the tree was fully typechecked I think we could check function usages better and add support for the class traversal -- but the former may be expensive because it may require another walk, and the later may actually not be a desired feature to support. |
I'm happy to come back and improve this later. Right now this'll at least catch a few more cases than we did before. |
@swift-ci Please smoke test |
@swift-ci Please smoke test |
1 similar comment
@swift-ci Please smoke test |
This PR walks the
VarDeclUsageChecker
onSourceFile.Decl
s to generate warnings for statements that aren't contained in abstract function declarations. This also disables the unused variable warnings for global variables since tracking global variables is complicated and felt like it was outside the scope of this bug.Resolves SR-2115.
I force pushed over my first attempt at this (#6971) to clean up history. I forgot it would kill the PR.