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
9

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
194

Why MD; that's usually a method decl.

200

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
152

I guess you can use hasSingleDecl in matcher to solve this

etienneb added inline comments.
clang-tidy/misc/UnnecessaryMutableCheck.cpp
38

nit: Decl *Declaration -> const Decl *Declaration

and other visitor functions.

40

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.

46

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

50

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

66

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

80

nit: HasRvalueCast -> HasRValueCast

85

if (Cast != nullptr) {

replace by

if (const auto* Cast = dyn_cast<ImplicitCastExpr>(ParMap->getParent(Expression)) {

and remove previous line.

99

nit: IsNonConstUseFound -> isNonConstUseFound
coding style wants lower case as first letter.

121

nit: remove this empty line

167

nit: remove { }

171

nit: remove { }

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

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
48

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
24

add an anonymous namespace around this declaration.

27

why getDeclName ?

43

Please add a comment to describe the purpose of this class.
The code is the doc, and it will help readers.

57

MemberExpr *Expression -> const auto*

61

thing -> object

63

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); }
135

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.

214

no need for ->getDeclName()
There is an overloaded operator for namedDecl.

218

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?