This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] Add misc-unnecessary-mutable check.
Needs ReviewPublic

Authored by mnbvmar on May 8 2016, 12:37 AM.

Details

Reviewers
Prazek
hokein
Summary

This implements unnecessary-mutable check. It's still bug-prone and might produce false positives, so all suggestions are welcome.

Diff Detail

Event Timeline

mnbvmar updated this revision to Diff 56513.May 8 2016, 12:37 AM
mnbvmar retitled this revision from to [clang-tidy] Add misc-unnecessary-mutable check..
mnbvmar updated this object.
mnbvmar added a reviewer: alexfh.
mnbvmar added subscribers: krystyna, sbarzowski, Prazek and 2 others.

Please mention this check in docs/ReleaseNotes.rst (in alphabetical order).

alexfh edited reviewers, added: hokein; removed: alexfh.May 11 2016, 10:47 AM
alexfh added a subscriber: alexfh.
alexfh added inline comments.
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:

  1. $ sudo apt-get install sphinx-common
  2. Enable LLVM_BUILD_DOCS and maybe some other options in cmake.
  3. $ ninja docs-clang-tools-html (or something similar, if you use make).

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).

Prazek added inline comments.
clang-tidy/misc/UnnecessaryMutableCheck.cpp
153

I guess you can use hasSingleDecl in matcher to solve this

etienneb added inline comments.
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;
ParMap = &LocalMap;
TraverseStmt(Body);
ParMap = nullptr; /// <-- I also prefer seeing this variable being after recursion.

47

Could we shortcut the recursion if "FoundNonConstUse" is true.
There is already a case found.

51

this "if" and the previous one should be merged.

67

As soon as something is "IsConstObj", they must be an early exit.
No need to continue iterations.

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
coding style wants lower case as first letter.

122

nit: remove this empty line

168

nit: remove { }

172

nit: remove { }

aaron.ballman added inline comments.May 14 2016, 11:00 AM
test/clang-tidy/misc-unnecessary-mutable.cpp
238

It would be good to put further information in about why this fails.

mnbvmar updated this revision to Diff 59445.Jun 2 2016, 12:44 PM

Fixes done.
Added macro test.
Docs should be working now.
Updated docs.

mnbvmar marked 14 inline comments as done.Jun 2 2016, 12:45 PM
mnbvmar added inline comments.Jun 2 2016, 12:53 PM
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.

etienneb added inline comments.Jun 3 2016, 8:41 AM
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.
The code is the doc, and it will help readers.

56

MemberExpr *Expression -> const auto*

60

thing -> object

62

I think the child-expressions of MemberExpr can only be "member->getBase()" ?
In this case, no loop is needed.

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).
hasBody() may return true, but the getBody() may be NULL.

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()
There is an overloaded operator for namedDecl.

217

You can change CheckRemoval to return the SourceRange.
If it's failing, you can call 'fixithint <<' and it won't be an issue.

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?