This implements unnecessary-mutable check. It's still bug-prone and might produce false positives, so all suggestions are welcome.
Diff Detail
Event Timeline
docs/clang-tidy/checks/misc-unnecessary-mutable.rst | ||
---|---|---|
10 | Please verify the documentation can be built without errors. On Ubuntu this boils down to: Install sphinx:
|
One quick thought: we should probably have a test that includes a macro to make sure nothing explodes. e.g.,
#define FIELD(T, N) mutable T N class C { FIELD(int, RemoveMutable); FIELD(int, KeepMutable) public: void haha() const { KeepMutable = 12; } };
Not that I expect to run into this case often, but it would be good to ensure the check doesn't crash or attempt to modify the macro.
clang-tidy/misc/UnnecessaryMutableCheck.cpp | ||
---|---|---|
195 | Why MD; that's usually a method decl. | |
201 | I think this would be more useful to hoist into the matcher itself (which may mean adding a new AST matcher first, if there isn't already one). |
clang-tidy/misc/UnnecessaryMutableCheck.cpp | ||
---|---|---|
153 | I guess you can use hasSingleDecl in matcher to solve this |
clang-tidy/misc/UnnecessaryMutableCheck.cpp | ||
---|---|---|
39 | nit: Decl *Declaration -> const Decl *Declaration and other visitor functions. | |
41 | Why not using stack memory instead of allocating memory? ParentMap LocalMap; | |
47 | Could we shortcut the recursion if "FoundNonConstUse" is true. | |
51 | this "if" and the previous one should be merged. | |
67 | As soon as something is "IsConstObj", they must be an early exit. | |
81 | nit: HasRvalueCast -> HasRValueCast | |
86 | if (Cast != nullptr) { replace by if (const auto* Cast = dyn_cast<ImplicitCastExpr>(ParMap->getParent(Expression)) { and remove previous line. | |
100 | nit: IsNonConstUseFound -> isNonConstUseFound | |
122 | nit: remove this empty line | |
168 | nit: remove { } | |
172 | nit: remove { } |
test/clang-tidy/misc-unnecessary-mutable.cpp | ||
---|---|---|
238 | It would be good to put further information in about why this fails. |
clang-tidy/misc/UnnecessaryMutableCheck.cpp | ||
---|---|---|
47 | Unless I miss something, the moment we set FoundNonConstUse to true, we stop recurring both in FieldUseVisitor and ClassMethodVisitor. |
clang-tidy/misc/UnnecessaryMutableCheck.cpp | ||
---|---|---|
23 | add an anonymous namespace around this declaration. | |
26 | why getDeclName ? | |
42 | Please add a comment to describe the purpose of this class. | |
56 | MemberExpr *Expression -> const auto* | |
60 | thing -> object | |
62 | I think the child-expressions of MemberExpr can only be "member->getBase()" ? child_range children() { return child_range(&Base, &Base+1); } Expr *getBase() const { return cast<Expr>(Base); } | |
134 | Watch out, Declaration->hasBody() is tricky with code when compile on windows (clang-cl). This is why these tests exist: cppcoreguidelines-pro-type-member-init-delayed.cpp modernize-redundant-void-arg-delayed.cpp modernize-use-default-delayed.cpp performance-unnecessary-value-param-delayed.cpp So this code may crash with delayed-template-parsing. | |
213 | no need for ->getDeclName() | |
217 | You can change CheckRemoval to return the SourceRange. This way, you do not need to declare Diag, and you can directly add the sourceRange to the expression to line 213. diag(FD->getLocation(), "'mutable' modifier is unnecessary for field %0") << FD << getSourceRangeOfMutableToken(FD); WDYT? |
add an anonymous namespace around this declaration.