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
[SR-7307] Warn when a block contains nothing but a defer statement #49855
Comments
Comment by Piyush Verma (JIRA) Hi All, |
I had only though of |
Comment by Piyush Verma (JIRA) @jckarter - I am interested in working on this Bug. Can I pick this as my starter bug? |
Sure! Let us know if you need any help getting started. |
Comment by Piyush Verma (JIRA) @jckarter - I am facing an issue. How do i get the reference of the immediate parent closure of defer block. Similar to `Optional<AnyFunctionRef> TheFunc` |
for the time being this bug is not assigned. I'll assign it to me and tackle it ( piverma (JIRA User), tell me if you still would like to work on this 😉 ). |
Comment by Piyush Verma (JIRA) Hi @vguerra , |
hello piverma (JIRA User) and @jckarter I have been trying to tackle this bug during the last weeks and the best I came up with, so far, is adding a check during the type checking phase. More specifically, when the My approach is very simple, emit a diagnostic message when a Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
const SourceManager &SM = TC.Context.SourceMgr;
if (BS->getNumElements() == 1) {
if (auto stmt = BS->getElement(0).dyn_cast<Stmt*>()) {
if (auto deferStmt = dyn_cast<DeferStmt>(stmt)) {
TC.diagnose(deferStmt->getStartLoc(), diag::defer_stmt_suggest_useless);
}
}
}
... this seems to do the job, except in the case when defer statements appear at the top level of the file: E.g.: using the following code: defer {
print("end of program.")
}
let x = 1
let y = 3
if (x > y) {
defer {
print("not so useful defer stmt.")
}
} would generate the following note messages: $> ./swiftc ../../../../examples/defer.swift
../../../../examples/defer.swift:1:1: note: defer statement is useless here
defer {
^
../../../../examples/defer.swift:9:5: note: defer statement is useless here
defer {
^ and this is due to the fact that all $> /swiftc -dump-ast ../../../../examples/defer.swift &> /tmp/ast.txt
(source_file
(top_level_code_decl
(brace_stmt
(defer_stmt
(func_decl implicit "$defer()" interface type='() -> ()' access=fileprivate
...
(top_level_code_decl
(brace_stmt
(pattern_binding_decl
(pattern_named type='Int' 'x')
...
(top_level_code_decl
(brace_stmt
(pattern_binding_decl
(pattern_named type='Int' 'y')
(top_level_code_decl
(brace_stmt
(if_stmt
... the first So what I am now trying to figure out is if there is a smarter way to check those I thought of taking advantage of the fact that Or maybe I took the wrong approach to solve this and there is another easier or more straight forward way to implement this ❓ 🙂. Any comments, suggestions and pointers are more than appreciated 😃 |
Comment by Piyush Verma (JIRA) Hi @vguerra , if (BS->getNumElements() > 0) {
if (auto stmt = BS->getElement(BS->getNumElements() - 1).dyn_cast<Stmt*>()) {
if (auto deferStmt = dyn_cast<DeferStmt>(stmt)) {
TC.diagnose(deferStmt->getStartLoc(), diag::defer_stmt_suggest_useless);
}
}
} to tackle condition (1) and (2) both. |
Comment by Piyush Verma (JIRA)
Can this check not help in the case mentioned by @vguerra ? Since its null for top level code. I mean: if (TheFunc.hasValue() && BS->getNumElements() > 0) {
if (auto stmt = BS->getElement(BS->getNumElements() - 1).dyn_cast<Stmt*>()) {
if (auto deferStmt = dyn_cast<DeferStmt>(stmt)) {
TC.diagnose(deferStmt->getStartLoc(), diag::defer_stmt_suggest_useless);
}
}
} |
hi! piverma (JIRA User) indeed checking for the last element under the Still, I am not sure how to solve the issue about |
Oh nice! .. I did not notice before that {{TheFunc}} is null for those cases 🙂. @jckarter is it safe to base the check on that assumption? |
hi piverma (JIRA User), unfortunately I dont think checking TheFunc.hasValue() is |
Comment by Piyush Verma (JIRA) @vguerra - Yeah, my apologies. It doesn't solve the issue. Also it might tend to ignore any defer at the end of the file. 🙁 |
piverma (JIRA User) no problem at all... thanks for pointing it out anyways 😉. |
It would probably be better to have the walker track whether you're in a `TopLevelCodeDecl`, by setting a flag while walking the `BraceStmt` of a `TopLevelCodeDecl`, than to try to check other incidental state. |
thank you @jckarter, will give that a try! |
hello all! I just opened a PR for this #17967 |
PR for this issue has been merged |
Awesome, thanks @vguerra! |
Additional Detail from JIRA
md5: 9b4fc281235964efdf067b80f3a93de4
Issue Description:
A user used to Go's defer, or expecting Go-like behavior from first principles, may write something like this:
which is going to run
thing_i_only_want_to_happen_when_x
at the exit of the if scope rather than at the end of the function. If a block contains nothing but a `defer`, the defer is useless, and we should probably warn to that effect.The text was updated successfully, but these errors were encountered: