Closed igor-akhmetov closed 4 years ago
There are multiple options here. In no particular order (and without any guarantees that these would actually work or would be desired features for the relevant tools):
It seems like the best workaround is to duplicate what 'cleanupAroundReplacements' is doing (copy-paste, rewrite to C#; it's open-source after all) in ReSharper and hope this function does not change too often (which is probably the case).
clang-apply-replacements is not really useful to us, as we'd like to be able to apply replacements inside the IDE itself. The usual workflow after applying a fix in an IDE is to change the text in the IDE buffer, not the physical file itself. The user can then evaluate the changes, and save the file when he wants to or revert the changes back.
The clang-apply-replacements tool can be used to apply a fix and cleanup.
For context, ReSharper/CLion run clang-tidy in an external process, in order to:
1) Be able to use custom user-provided clang-tidy binaries. 2) Be resilient to clang crashes.
It is also desirable to be able to apply a fix for a specific single inspection from the IDE. This means we can't use cleanupAroundReplacements with the current clang-tidy CLI. To do that we'd need to teach the clang-tidy to apply a single fix (--line-filter is insufficient for that), and to print the resulting replacements together with replacements from cleanupAroundReplacements instead of applying them to the physical file.
An alternative check implementation would output a single check result for a given initialization list which would contain several fixes for all the redundant initializers (so that additional cleanup would not be necessary), but I do understand that the current design is simpler.
The cleanup is implemented in the clang::format::cleanupAroundReplacements function. clang-tidy calls it here: clang-tidy/ClangTidy.cpp:205. Cleanup is done separately from producing the fixes, since it may become necessary when applying multiple independent fixes together, e.g. consider this code:
... A() : a(...), b(...), c(...) {} ...
If three different checks independently try to remove initializers for a
, b
and c
, which of them should remove commas and the semicolon? If we decide, that the check should remove the comma after an initializer list member, then when removing c(...)
, we'll not be able to remove a comma after it, but we'll leave a comma before it. Same if we decide to remove a comma before the member (now the issue is with a(...)
). Same with the semicolon (we only need to remove it, when removing all initializer list items.
A similar problem exists for inserting/removing #include directives.
We can't clean up replacements when exporting them, because they are grouped by diagnostic and can be applied one by one.
The only good solution is for the tool that applies the fix to clean up code. If ReSharper doesn't do this, it's wrong. It should call clang::format::cleanupAroundReplacements before applying replacements.
Thanks, I was not aware that some additional cleanup is taking place. Is it performed by clang-format, or by some logic in clang-tidy itself?
I'm using ReSharper C++, which just applies the fixit provided by clang-tidy. In this case the text edit is:
MainSourceFile: 'C:\tmp\ConsoleApplication19\ConsoleApplication19.cpp'
Diagnostics:
- DiagnosticName: readability-redundant-member-init
DiagnosticMessage:
Message: 'initializer for member ''s'' is redundant'
FilePath: 'C:\tmp\ConsoleApplication19\ConsoleApplication19.cpp'
FileOffset: 53
Replacements:
- FilePath: 'C:\tmp\ConsoleApplication19\ConsoleApplication19.cpp'
Offset: 53
Length: 4
ReplacementText: ''
That said, it should be possible to change the fixit provided by this check so that no additional cleanup is necessary. This would help all external tools that consume clang-tidy fixits.
Clang-tidy checks produce fixes that sometimes need to be cleaned up to remove redundant colons or commas.
The cleanup is performed after applying the fixes.
clang-tidy 9 performs this cleanup correctly:
$ cat test.cpp
class Foo { public: Foo() : s() {}
private: std::string s; };
$ clang-tidy-9 --checks=readability-redundant-member-init test.cpp --fix -- 1 warning generated. test.cpp:5:11: warning: initializer for member 's' is redundant [readability-redundant-member-init] Foo() : s() {} ^~~~ test.cpp:5:11: note: FIX-IT applied suggested code changes clang-tidy applied 1 of 1 suggested fixes.
$ cat test.cpp
class Foo { public: Foo() {}
private: std::string s; };
Which tool are you using to apply the fixes?
assigned to @pepsiman
Extended Description
With clang-tidy 9 apply fix to the example from the check documentation:
class Foo { public: Foo() : s() {}
private: std::string s; };
Result:
class Foo { public: Foo() : {}
private: std::string s; };