mnbvmar created this revision.
mnbvmar added a reviewer: alexfh.
mnbvmar added subscribers: krystyna, sbarzowski, Prazek, staronj, cfe-commits.

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

http://reviews.llvm.org/D20053

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UnnecessaryMutableCheck.cpp
  clang-tidy/misc/UnnecessaryMutableCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-unnecessary-mutable.rst
  test/clang-tidy/misc-unnecessary-mutable.cpp

Index: test/clang-tidy/misc-unnecessary-mutable.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-unnecessary-mutable.cpp
@@ -0,0 +1,354 @@
+// RUN: %check_clang_tidy %s misc-unnecessary-mutable %t
+
+struct NothingMutable {
+  int field1;
+  unsigned field2;
+  const int field3;
+  volatile float field4;
+
+  NothingMutable(int a1, unsigned a2, int a3, float a4) : field1(a1), field2(a2), field3(a3), field4(a4) {}
+
+  void doSomething() {
+    field1 = 1;
+    field2 = 2;
+    field4 = 4;
+  }
+};
+
+struct NoMethods {
+  int field1;
+  mutable unsigned field2; // These cannot be fixed; they're public
+  const int field3;
+  mutable volatile NothingMutable field4;
+};
+
+class NoMethodsClass {
+public:
+  int field1;
+  mutable unsigned field2;
+
+private:
+  const int field3;
+  mutable volatile NothingMutable field4;
+  // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'mutable' modifier is unnecessary for field 'field4' [misc-unnecessary-mutable]
+  // CHECK-FIXES: {{^  }}volatile NothingMutable field4;
+};
+
+struct PrivateInStruct {
+private:
+  mutable volatile unsigned long long blah;
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: 'mutable' modifier is unnecessary for field 'blah' {{..}}
+  // CHECK-FIXES: {{^  }}volatile unsigned long long blah;
+};
+
+union PrivateInUnion {
+public:
+  int someField;
+
+private:
+  mutable char otherField;
+};
+
+class UnusedVar {
+private:
+  mutable int x __attribute__((unused));
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'mutable' modifier is unnecessary for field 'x' {{..}}
+  // CHECK-FIXES: {{^  }}int x __attribute__((unused));
+};
+
+class NoConstMethodsClass {
+public:
+  int field1;
+  mutable unsigned field2;
+
+  NoConstMethodsClass() : field2(42), field3(9), field4(NothingMutable(1, 2, 3, 4)) {}
+
+  void doSomething() {
+    field2 = 8;
+    field1 = 99;
+    field4.doSomething();
+  }
+
+private:
+  const int field3;
+  mutable NothingMutable field4;
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 'mutable' modifier is unnecessary for field 'field4' {{..}}
+  // CHECK-FIXES: {{^  }}NothingMutable field4;
+};
+
+class ConstMethods {
+private:
+  mutable int field1, field2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'mutable' modifier is unnecessary for field 'field2' {{..}}
+  mutable int incr, decr, set, mul, constArg1, constArg2, constRef, ref1, ref2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'mutable' modifier is unnecessary for field 'constArg1' {{..}}
+  // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: 'mutable' modifier is unnecessary for field 'constArg2' {{..}}
+  // CHECK-MESSAGES: :[[@LINE-3]]:59: warning: 'mutable' modifier is unnecessary for field 'constRef' {{..}}
+
+  void takeArg(int x) const { x *= 4; }
+  int takeConstRef(const int &x) const { return x + 99; }
+  void takeRef(int &) const {}
+
+  template <typename... Args>
+  void takeArgs(Args... args) const {}
+  template <typename... Args>
+  void takeArgRefs(Args &... args) const {}
+
+public:
+  void doSomething() const {
+    field1 = field2;
+  }
+
+  void doOtherThing() const {
+    incr++;
+    decr--;
+    set = 42;
+    mul *= 3;
+    takeArg(constArg1);
+    takeConstRef(constRef);
+    takeRef(ref1);
+    takeArgs(constArg1, constArg2);
+    takeArgRefs(ref1, ref2);
+  }
+};
+
+class NonFinalClass {
+public:
+  mutable int fPublic;
+
+protected:
+  mutable int fProtected;
+
+private:
+  mutable int fPrivate;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'mutable' modifier is unnecessary for field 'fPrivate' {{..}}
+  // CHECK-FIXES: {{^  }}int fPrivate;
+};
+
+class FinalClass final {
+public:
+  mutable int fPublic;
+
+protected:
+  mutable int fProtected;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'mutable' modifier is unnecessary for field 'fProtected' {{..}}
+  // CHECK-FIXES: {{^  }}int fProtected;
+
+private:
+  mutable int fPrivate;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'mutable' modifier is unnecessary for field 'fPrivate' {{..}}
+  // CHECK-FIXES: {{^  }}int fPrivate;
+};
+
+class NotAllFuncsKnown {
+  void doSomething();
+  void doSomethingConst() const {}
+
+private:
+  mutable int field;
+  // Can't be fixed. We don't know if doSomething() doesn't declare a *const* NotAllFuncsKnown instance
+  // and then modify 'field' field.
+};
+
+class NotAllConstFuncsKnown {
+  void doSomething() {}
+  void doSomethingConst() const;
+  void doOtherConst() const {}
+
+private:
+  mutable int field;
+};
+
+class ConstFuncOutside {
+  void doSomething();
+  void doSomethingConst() const;
+  void doOtherConst() const {}
+
+private:
+  mutable int field;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'mutable' modifier is unnecessary for field 'field' {{..}}
+  // CHECK-FIXES: {{^  }}int field;
+};
+
+void ConstFuncOutside::doSomethingConst() const {}
+
+// We can't really see if mutable is necessary or not.
+template <typename T>
+class TemplatedClass {
+public:
+  void doSomething() {
+    a = b = c;
+  }
+
+  void doSomethingConst() const {
+    a = b = c;
+  }
+
+private:
+  mutable int a, b, c;
+};
+
+TemplatedClass<int> TemplatedClassInt;
+
+class ClassWithTemplates {
+public:
+  void doSomethingConst() const {
+    a = b;
+  }
+
+  // Here, we can see that.
+  template <typename T>
+  void doOtherConst() const {
+    b = c;
+  }
+
+private:
+  mutable int a, b, c, d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'mutable' modifier is unnecessary for field 'c' {{..}}
+  // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: 'mutable' modifier is unnecessary for field 'd' {{..}}
+};
+
+class ImplicitCast {
+public:
+  void doSomethingConst() const {
+    a = b;
+  }
+
+private:
+  mutable int a;
+  mutable double b;
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'mutable' modifier is unnecessary for field 'b' {{..}}
+  // CHECK_FIXES: {{^  }}double b;
+};
+
+struct MutableNotFirst {
+private:
+  long mutable long abc = 42;
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'mutable' modifier is unnecessary for field 'abc' {{..}}
+  // CHECK_FIXES: {{^  }}long long abc;
+  long long mutable bca;
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'mutable' modifier is unnecessary for field 'bca' {{..}}
+  // CHECK_FIXES: {{^  }}long long bca;
+  int mutable ca;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: 'mutable' modifier is unnecessary for field 'ca' {{..}}
+  // CHECK_FIXES: {{^  }}int ca;
+};
+
+// Fails for now.
+/*
+void change(const int &a) {
+    const_cast<int&>(a) = 42;
+}
+
+struct Change {
+    void changeMember() const {
+        change(m);
+        const int& x = otherM;
+        const_cast<int&>(x) = 33;
+
+        const_cast<int&>(anotherM) = -4;
+    }
+private:
+    mutable int m;        
+    mutable int otherM;
+    mutable int anotherM;
+};
+*/
+
+class StrangeClass {
+public:
+  void foo() {}
+};
+
+void EvilFunction(int &a) {}
+void EvilFunction(const int &a) {}
+
+class JustClass {
+public:
+  JustClass() {}
+
+  void foo() {
+    MutableClass.foo();
+  }
+
+  void foo() const;
+  void evilCaller() const;
+
+private:
+  mutable StrangeClass MutableClass; // Must stay mutable (because of foo func below)
+  mutable int MutableInt;            // Must stay mutable
+};
+
+void JustClass::foo() const {
+  MutableClass.foo();
+}
+
+void JustClass::evilCaller() const {
+  EvilFunction(MutableInt);
+}
+
+class AnotherStrangeClass {
+public:
+  // Example of non-const method which requires that MutableInt should stay mutable.
+  void strangeFoo() {
+    const AnotherStrangeClass *ConstThis = this;
+    EvilFunction(ConstThis->MutableInt);
+  }
+
+private:
+  mutable int MutableInt; // must stay mutable
+};
+
+class ClassWithStrangeConstructor {
+public:
+  ClassWithStrangeConstructor() {
+    const ClassWithStrangeConstructor *ConstThis = this;
+    EvilFunction(ConstThis->MutableInt);
+  }
+
+private:
+  mutable int MutableInt; // must stay mutable
+};
+
+class ClassWithStrangeDestructor {
+public:
+  ~ClassWithStrangeDestructor() {
+    const ClassWithStrangeDestructor *ConstThis = this;
+    EvilFunction(ConstThis->MutableInt);
+  }
+
+private:
+  mutable int MutableInt; // must stay mutable
+};
+
+// Don't touch friends or they'll hurt you.
+class ClassWithFriends {
+public:
+  friend void someFriend(ClassWithFriends *);
+
+private:
+  mutable int MutableInt; // must stay mutable
+};
+
+void someFriend(ClassWithFriends *Class) {
+  const ClassWithFriends *ConstClass = Class;
+  EvilFunction(ConstClass->MutableInt);
+}
+
+class ClassWithClassFriends {
+public:
+  friend class ClassFriend;
+
+private:
+  mutable int MutableInt; // must stay mutable
+};
+
+class ClassFriend {
+public:
+  static void foo(const ClassWithClassFriends *Class) {
+    EvilFunction(Class->MutableInt);
+  }
+
+private:
+  mutable int m;
+};
Index: docs/clang-tidy/checks/misc-unnecessary-mutable.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/misc-unnecessary-mutable.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - misc-unnecessary-mutable
+
+misc-unnecessary-mutable
+========================
+
+The tool tries to find situations where ``mutable`` might be unnecessary
+(i.e. each use of the mutable field on the const object is constant).
+
+.. code-block:: c++
+  class SomeClass {
+    public:
+      void foo() {
+        field2 = 42;
+      }
+
+      void bar() const {
+        field3 = 99;
+      }
+
+      // Should stay mutable. Everyone can change it.
+      mutable int field1;
+
+    private:
+      // Might lose 'mutable'. It's never modified in const object.
+      mutable int field2;
+
+      // Should stay mutable; bar() changes it even though 'this' is const.
+      mutable int field3;
+  };
+
+It also can automatically remove ``mutable`` keyword. For now, it is done
+only if non-necessarily mutable field is the only declaration in the statement.
+
+Please note that there is a possibility that false-positives occur. For example,
+one can use ``const_cast``:
+
+.. code-block:: c++
+  class AnotherClass {
+    public:
+      void foo() const {
+        const int& y = x;
+        const_cast<int&>(y) = 42;
+      }
+
+    private:
+      mutable int x; // SHOULD stay mutable. For now, it does not.
+  };
+
+The tool should be thus used with care.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -85,6 +85,7 @@
    misc-throw-by-value-catch-by-reference
    misc-undelegated-constructor
    misc-uniqueptr-reset-release
+   misc-unnecessary-mutable
    misc-unused-alias-decls
    misc-unused-parameters
    misc-unused-raii
Index: clang-tidy/misc/UnnecessaryMutableCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/UnnecessaryMutableCheck.h
@@ -0,0 +1,43 @@
+//===--- UnnecessaryMutableCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNNECESSARY_MUTABLE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNNECESSARY_MUTABLE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Searches for and removes unnecessary 'mutable' keywords (that is, for
+/// fields that cannot be possibly changed in const methods).
+///
+/// Example:
+///
+/// class MyClass {
+///   mutable int field;  // will change into "int field;"
+/// };
+///
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unnecessary-mutable.html
+class UnnecessaryMutableCheck : public ClangTidyCheck {
+public:
+  UnnecessaryMutableCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNNECESSARY_MUTABLE_H
Index: clang-tidy/misc/UnnecessaryMutableCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/UnnecessaryMutableCheck.cpp
@@ -0,0 +1,223 @@
+//===--- UnnecessaryMutableCheck.cpp - clang-tidy--------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnnecessaryMutableCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void UnnecessaryMutableCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      fieldDecl(anyOf(isPrivate(), allOf(isProtected(),
+                                         hasParent(cxxRecordDecl(isFinal())))),
+                unless(anyOf(isImplicit(), isInstantiated(),
+                             hasParent(cxxRecordDecl(isUnion())))))
+          .bind("field"),
+      this);
+}
+
+class FieldUseVisitor : public RecursiveASTVisitor<FieldUseVisitor> {
+public:
+  explicit FieldUseVisitor(FieldDecl *SoughtField)
+      : SoughtField(SoughtField), FoundNonConstUse(false) {}
+
+  void RunSearch(Decl *Declaration) {
+    auto *Body = Declaration->getBody();
+    ParMap = new ParentMap(Body);
+    TraverseStmt(Body);
+    delete ParMap;
+  }
+
+  bool VisitExpr(Expr *GenericExpr) {
+    MemberExpr *Expression = dyn_cast<MemberExpr>(GenericExpr);
+    if (Expression == nullptr)
+      return true;
+
+    if (Expression->getMemberDecl() != SoughtField)
+      return true;
+
+    // Check if expr is a member of const thing.
+    bool IsConstObj = false;
+    for (auto *ChildStmt : Expression->children()) {
+      Expr *ChildExpr = dyn_cast<Expr>(ChildStmt);
+      if (ChildExpr) {
+        IsConstObj |= ChildExpr->getType().isConstQualified();
+
+        // If member expression dereferences, we need to check
+        // whether pointer type is const.
+        if (Expression->isArrow()) {
+          auto &WrappedType = *ChildExpr->getType();
+          if (!WrappedType.isPointerType()) {
+            // It's something weird. Just to be sure, assume we're const.
+            IsConstObj = true;
+          } else {
+            IsConstObj |= WrappedType.getPointeeType().isConstQualified();
+          }
+        }
+      }
+    }
+
+    // If it's not, mutableness changes nothing.
+    if (!IsConstObj)
+      return true;
+
+    // By a const operation on a member expression we mean a MemberExpr
+    // whose parent is ImplicitCastExpr to rvalue or something constant.
+    bool HasRvalueCast = false;
+    bool HasConstCast = false;
+    if (ParMap->hasParent(Expression)) {
+      const auto *Cast =
+          dyn_cast<ImplicitCastExpr>(ParMap->getParent(Expression));
+      if (Cast != nullptr) {
+        HasRvalueCast = Cast->getCastKind() == CastKind::CK_LValueToRValue;
+        HasConstCast = Cast->getType().isConstQualified();
+      }
+    }
+
+    if (!HasRvalueCast && !HasConstCast) {
+      FoundNonConstUse = true;
+      return false;
+    }
+
+    return true;
+  }
+
+  bool IsNonConstUseFound() const { return FoundNonConstUse; }
+
+private:
+  FieldDecl *SoughtField;
+  ParentMap *ParMap;
+  bool FoundNonConstUse;
+};
+
+class ClassMethodVisitor : public RecursiveASTVisitor<ClassMethodVisitor> {
+public:
+  ClassMethodVisitor(ASTContext &Context, FieldDecl *SoughtField)
+      : SM(Context.getSourceManager()), SoughtField(SoughtField),
+        NecessaryMutable(false) {}
+
+  bool VisitDecl(Decl *GenericDecl) {
+    // As for now, we can't track friends.
+    if (dyn_cast<FriendDecl>(GenericDecl)) {
+      NecessaryMutable = true;
+      return false;
+    }
+
+    FunctionDecl *Declaration = dyn_cast<FunctionDecl>(GenericDecl);
+
+    if (Declaration == nullptr)
+      return true;
+
+    // All decls need their definitions in main file.
+    if (!Declaration->hasBody() ||
+        !SM.isInMainFile(Declaration->getBody()->getLocStart())) {
+      NecessaryMutable = true;
+      return false;
+    }
+
+    FieldUseVisitor FieldVisitor(SoughtField);
+    FieldVisitor.RunSearch(Declaration);
+    if (FieldVisitor.IsNonConstUseFound()) {
+      NecessaryMutable = true;
+      return false;
+    }
+
+    return true;
+  }
+
+  bool IsMutableNecessary() const { return NecessaryMutable; }
+
+private:
+  SourceManager &SM;
+  FieldDecl *SoughtField;
+  bool NecessaryMutable;
+};
+
+// Checks if 'mutable' keyword can be removed; for now; we do it only if
+// it is the only declaration in a declaration chain.
+static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart,
+                         const SourceLocation &LocEnd, ASTContext &Context,
+                         SourceRange &ResultRange) {
+
+  FileID FID = SM.getFileID(LocEnd);
+  llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd);
+  Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(),
+                  Buffer->getBufferStart(), SM.getCharacterData(LocStart),
+                  Buffer->getBufferEnd());
+
+  Token DeclToken;
+  bool result = false;
+
+  while (!DeclLexer.LexFromRawLexer(DeclToken)) {
+
+    if (DeclToken.getKind() == tok::TokenKind::semi) {
+      break;
+    }
+
+    if (DeclToken.getKind() == tok::TokenKind::comma) {
+      return false;
+    }
+
+    if (DeclToken.isOneOf(tok::TokenKind::identifier,
+                          tok::TokenKind::raw_identifier)) {
+      auto TokenStr = DeclToken.getRawIdentifier().str();
+
+      // "mutable" cannot be used in any other way than to mark mutableness
+      if (TokenStr == "mutable") {
+        ResultRange =
+            SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc());
+        result = true;
+      }
+    }
+  }
+
+  assert(result && "No mutable found, weird");
+
+  return result;
+}
+
+void UnnecessaryMutableCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *MD = Result.Nodes.getNodeAs<FieldDecl>("field");
+  const auto *ClassMatch = dyn_cast<CXXRecordDecl>(MD->getParent());
+  auto &Context = *Result.Context;
+  auto &SM = *Result.SourceManager;
+
+  if (!MD->getDeclName() || ClassMatch->isDependentContext() ||
+      !MD->isMutable())
+    return;
+
+  ClassMethodVisitor Visitor(Context, const_cast<FieldDecl *>(MD));
+  Visitor.TraverseDecl(const_cast<CXXRecordDecl *>(ClassMatch));
+
+  if (Visitor.IsMutableNecessary())
+    return;
+
+  auto Diag =
+      diag(MD->getLocation(), "'mutable' modifier is unnecessary for field %0")
+      << MD->getDeclName();
+
+  SourceRange RemovalRange;
+
+  if (CheckRemoval(SM, MD->getLocStart(), MD->getLocEnd(), Context,
+                   RemovalRange)) {
+    Diag << FixItHint::CreateRemoval(RemovalRange);
+  }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -45,6 +45,7 @@
 #include "ThrowByValueCatchByReferenceCheck.h"
 #include "UndelegatedConstructor.h"
 #include "UniqueptrResetReleaseCheck.h"
+#include "UnnecessaryMutableCheck.h"
 #include "UnusedAliasDeclsCheck.h"
 #include "UnusedParametersCheck.h"
 #include "UnusedRAIICheck.h"
@@ -126,6 +127,8 @@
         "misc-undelegated-constructor");
     CheckFactories.registerCheck<UniqueptrResetReleaseCheck>(
         "misc-uniqueptr-reset-release");
+    CheckFactories.registerCheck<UnnecessaryMutableCheck>(
+        "misc-unnecessary-mutable");
     CheckFactories.registerCheck<UnusedAliasDeclsCheck>(
         "misc-unused-alias-decls");
     CheckFactories.registerCheck<UnusedParametersCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -37,6 +37,7 @@
   ThrowByValueCatchByReferenceCheck.cpp
   UndelegatedConstructor.cpp
   UniqueptrResetReleaseCheck.cpp
+  UnnecessaryMutableCheck.cpp
   UnusedAliasDeclsCheck.cpp
   UnusedParametersCheck.cpp
   UnusedRAIICheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to