The define out of line refactor tool previously would copy the virtual, override and final specifier into the out of line method definition.
This results in malformed code as those specifiers aren't allowed outside the class definition.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Thanks for working on this!
A few comments on macro handling and coding style. Apart from that mostly needs more testing.
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
216 | nit: auto DelAttr = [&](const Attr* A) { /* do magic */}; if(auto *OA = FD->getAttr<OverrideAttr>()) DelAttr(OA); if(auto *FA = ...) | |
219 | can you rather use auto AttrToken = TB.getSpelledTokens(TB.getExpandedTokens(Attr.getRange())); throughout this part. | |
220 | can you add some test cases for this branch ? In theory it should be ok to drop this if full expansion is just the attr, i.e. #define FNL final struct A { virtual void foo() FNL {} }; but should possibly fail in : #define MACRO foo() final struct A { virtual void MACRO {} }; | |
236 | nit: I believe QualifierInsertions needs to be renamed now, maybe something like DeclarationCleanups ? | |
244 | again could you please add tests checking this case? | |
246 | you would rather want to go over spelled tokens, as expandedtokens might not exist in the source code. (it looks like the usage above, not related to this patch, is also broken. No need to fix that one I'll try to prepare a fix, but patches welcome.) TokBuf.spelledForExpanded(TokBuf.expandedTokens(SpecRange)) | |
247 | nit: use early exits, i.e: if(Tok.kind() != tok::kw_virtual) continue; `` | |
249 | same argument as above. | |
260 | you can use Tok.range(SM) instead | |
clang-tools-extra/clangd/unittests/TweakTests.cpp | ||
2113 | can you also add a test case for final override/override final |
I'm not entirely sure how to get the spelledTokens working in a good macro safe way?
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
220 | it's not a great idea refactoring functions with MACRO attributes, we can never know if there are side effects based on different definitions due to things like build configs. |
I don't really follow this comment, could you elaborate? TB.expandedTokens always refer to a subset of the pre-processed token stream, so they can contain non-spelled tokens therefore clangd should never try to operate on those tokens. For example:
#define FOO(X) int X; FOO(y);
pre-processed token stream will only contain int y which doesn't exist in the source code at all. TB.spelledForExpanded tries to map those expanded range back to spelling (to FOO(y) for example if you've got the full range int y), which is safe to operate on.
if there's no direct mapping between selected range and source code then it returns None, so you should bail out in such cases.
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
220 | well that's definitely one way to go, but while designing this code action we decided user should know better and clangd currently provides this code action in cases involving macros, see DefineOutlineTest.HandleMacros and it would be inconsistent with rest of the behavior if it bailed out in half of the cases and kept working for the rest. Also this case is even safer than the rest, since it is only trying to drop those qualifiers and not duplicate them in the definition side. | |
244 | sorry, i still don't see any cases with multiple virtual keywords. |
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
220 | Thanks for explaining that for me, I'll give it a go and see how the test cases are handled | |
244 | Ah I thought you meant a test case just containing virtual which there is, I'll get the second one added. |
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
244 | If compiler has an error parsing those, we'll be on the safe side since AST will be broken for that node and we'll most likely bail out long before we reach here. If compiler is happy with those, and produces just warnings, deleting one vs deleting multiple shouldn't make much difference in the code path(just a matter of breaking or not), but would make action more resilient so I would go for deleting multiple, since it won't have any side effects the user will still see the compiler warning in the header(declaration location). |
- Fixed clang tidy warning, wont fix format as it's contradicting with the style of the rest of the function
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
231 | let's use syntax::Token::range(SM, AttrTokens->front(), AttrTokens->back())... instead | |
253 | what about setting Any to true below this check and just breaking here instead? e.g. bool Any = false; for(...) { .... if (!Spelling) break; Any = true; } if (!Any) appendToErrors | |
261 | why assert on this and not delete the whole Spelling that produced the virtual keyword ? e.g. #define STUPID_MACRO(X) virtual struct F { STUPID_MACRO(BLA BLA) void foo(); } |
I believe the formatting linter messages results from the fact that you are finishing the structs with a } on a newline, it should be right next to expected output, without any newlines in between.
The linter messages are actually to do with the no new line after the { and bad indentation inside the braced init list, however that's how the rest look.
yes it just suggests a formatting, but the formatting you want is dropping the new line just before } and hopefully that should also make linter happy.
Thanks, LGTM with a few small comments, please address those before landing.
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp | ||
---|---|---|
244 | double negation is bad(this already looks confusing, sounds like we start in an errorful state?) I think we should rather have HadErrors | |
261 | sorry for not explicitly asking in the previous one, could you also add a test for this case? | |
clang-tools-extra/clangd/unittests/TweakTests.cpp | ||
2175 | you also need to delete the comma just before the } |
nit: