firolino updated this revision to Diff 81730.
firolino added a comment.

little cleanup in getUserWrittenType


https://reviews.llvm.org/D27621

Files:
  clang-tidy/readability/CMakeLists.txt
  clang-tidy/readability/OneNamePerDeclarationCheck.cpp
  clang-tidy/readability/OneNamePerDeclarationCheck.h
  clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tidy/utils/LexerUtils.cpp
  clang-tidy/utils/LexerUtils.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/readability-one-name-per-declaration.rst
  test/clang-tidy/readability-one-name-per-declaration-complex.cpp
  test/clang-tidy/readability-one-name-per-declaration-modern.cpp
  test/clang-tidy/readability-one-name-per-declaration-simple.cpp

Index: test/clang-tidy/readability-one-name-per-declaration-simple.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/readability-one-name-per-declaration-simple.cpp
@@ -0,0 +1,142 @@
+// RUN: %check_clang_tidy %s readability-one-name-per-declaration %t
+
+int cantTouchA, cantTouchB;
+
+void simple() 
+{
+    int dontTouchC;
+    
+    long empty;
+    long long1 = 11, *long2 = &empty, * long3 = ∅
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}long long1 = 11;
+    // CHECK-FIXES: {{^    }}long *long2 = ∅
+    // CHECK-FIXES: {{^    }}long * long3 = ∅
+    
+    long ** lint1, lint2 = 0, * lint3, **linn;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}long ** lint1;
+    // CHECK-FIXES: {{^    }}long lint2 = 0;
+    // CHECK-FIXES: {{^    }}long * lint3;
+    // CHECK-FIXES: {{^    }}long **linn;
+    
+    	long int* lint4, *lint5,  lint6;
+    	// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    	// CHECK-FIXES: {{^    	}}long int* lint4;
+    	// CHECK-FIXES: {{^    	}}long int *lint5;
+    	// CHECK-FIXES: {{^    	}}long int lint6;
+    
+    /* *& */ int /* *& */ ** /* *& */ pp,*xx;
+    // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}/* *& */ int /* *& */ ** /* *& */ pp;
+    // CHECK-FIXES: {{^    }}int *xx;
+    
+    unsigned int uint1 = 0,uint2 = 44u, uint3, uint4=4;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}unsigned int uint1 = 0;
+    // CHECK-FIXES: {{^    }}unsigned int uint2 = 44u;
+    // CHECK-FIXES: {{^    }}unsigned int uint3;
+    // CHECK-FIXES: {{^    }}unsigned int uint4=4;
+    
+    const int * const cpc = &dontTouchC, simple = 0;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int * const cpc = &dontTouchC;
+    // CHECK-FIXES: {{^    }}const int simple = 0;
+    
+    double darray1[] = {}, darray2[] = {1,	2},dv1 = 3,dv2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}double darray1[] = {};
+    // CHECK-FIXES: {{^    }}double darray2[] = {1,	2};
+    // CHECK-FIXES: {{^    }}double dv1 = 3;
+    // CHECK-FIXES: {{^    }}double dv2;
+    
+    int notransform[] =   {
+                              1,
+                              2
+                          };
+    
+    const int cx = 1, cy = 2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int cx = 1;
+    // CHECK-FIXES: {{^    }}const int cy = 2;
+    
+    volatile int vx, vy;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}volatile int vx;
+    // CHECK-FIXES: {{^    }}volatile int vy;
+    
+    signed char sc1 = 'h', sc2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}signed char sc1 = 'h';
+    // CHECK-FIXES: {{^    }}signed char sc2;
+    
+    long long ll1, ll2, ***ft;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}long long ll1;
+    // CHECK-FIXES: {{^    }}long long ll2;
+    // CHECK-FIXES: {{^    }}long long ***ft;
+    
+    const char *cstr1 = "str1", *cstr2="str2";
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const char *cstr1 = "str1";
+    // CHECK-FIXES: {{^    }}const char *cstr2="str2";
+    
+    const char *literal1 = "clang"		"test" \
+                           "one",
+               *literal2 = "empty", literal3[] = "three";
+    // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const char *literal1 = "clang"		"test" \
+    // CHECK-FIXES: {{^                           }}"one";
+    // CHECK-FIXES: {{^    }}const char *literal2 = "empty";
+    // CHECK-FIXES: {{^    }}const char literal3[] = "three";
+    
+    int intarray[] =
+          {
+           			1,
+                    2,
+                    3,
+                    4
+          }, bb = 5;
+    // CHECK-MESSAGES: :[[@LINE-7]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int intarray[] =
+    // CHECK-FIXES: {{^    }}      {
+    // CHECK-FIXES: {{^    }}       			1,
+    // CHECK-FIXES: {{^    }}                2,
+    // CHECK-FIXES: {{^    }}                3,
+    // CHECK-FIXES: {{^    }}                4
+    // CHECK-FIXES: {{^    }}      };
+    // CHECK-FIXES: {{^    }}int bb = 5;
+    
+    const int cint3 = 4, cintarray[] = { 1, 2, 3, 4 };
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int cint3 = 4;
+    // CHECK-FIXES: {{^    }}const int cintarray[] = { 1, 2, 3, 4 };
+
+    union {
+        int m1;
+        float m2;
+    } in, out;
+    
+    int refme1;
+    int refme2 = 0;
+    const int &r1 = refme1, &r2 = refme2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int &r1 = refme1;
+    // CHECK-FIXES: {{^    }}const int &r2 = refme2;
+    
+    typedef int ta, tb;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef int ta;
+    // CHECK-FIXES: {{^    }}typedef int tb;
+    
+    typedef const int tca, tcb;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef const int tca;
+    // CHECK-FIXES: {{^    }}typedef const int tcb;
+    
+    typedef int const tac, tbc;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef int const tac;
+    // CHECK-FIXES: {{^    }}typedef int const tbc;
+}
+
Index: test/clang-tidy/readability-one-name-per-declaration-modern.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/readability-one-name-per-declaration-modern.cpp
@@ -0,0 +1,83 @@
+// RUN: %check_clang_tidy %s readability-one-name-per-declaration %t -- -- \
+// RUN:   -std=c++1y
+
+namespace std {    
+    template <typename T>
+    class initializer_list {};
+    
+    template <typename T>
+    class vector 
+    {
+      public:
+        vector() = default;
+        vector(initializer_list<T> init) {}
+    };
+    
+    class string 
+    {
+      public:
+        string() = default;
+        string(const char*) {}
+    };
+    
+    namespace string_literals {    
+        string operator""s(const char*, decltype(sizeof(int))) 
+        {   
+            return string(); 
+        }
+    }
+}
+
+namespace Types {    
+    typedef int MyType;    
+    int dontTouch1, dontTouch2;
+}
+
+void modern() 
+{
+    auto autoInt1 = 3, autoInt2 = 4;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}auto autoInt1 = 3;
+    // CHECK-FIXES: {{^....}}auto autoInt2 = 4;
+    
+    decltype(int()) declnottouch= 4;
+    
+    decltype(int()) declint1 = 5, declint2 = 3;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]    
+    // CHECK-FIXES: {{^....}}decltype(int()) declint1 = 5;
+    // CHECK-FIXES: {{^....}}decltype(int()) declint2 = 3;
+    
+    std::vector<int> vectorA = {1,2}, vectorB = {1,2,3}, vectorC({1,1,1});
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}std::vector<int> vectorA = {1,2};
+    // CHECK-FIXES: {{^....}}std::vector<int> vectorB = {1,2,3};
+    // CHECK-FIXES: {{^....}}std::vector<int> vectorC({1,1,1});
+    
+    using uType = int;
+    uType utype1, utype2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}uType utype1;
+    // CHECK-FIXES: {{^....}}uType utype2;
+    
+    Types::MyType mytype1, mytype2, mytype3 = 3;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}Types::MyType mytype1;
+    // CHECK-FIXES: {{^....}}Types::MyType mytype2;
+    // CHECK-FIXES: {{^....}}Types::MyType mytype3 = 3;
+    
+    {
+        using namespace std::string_literals;
+        
+        std::vector<std::string> s{"foo"s, "bar"s}, t{"foo"s}, u, a({"hey", "you"}), bb = {"h", "a" };
+        // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+        // CHECK-FIXES: {{^        }}std::vector<std::string> s{"foo"s, "bar"s};
+        // CHECK-FIXES: {{^        }}std::vector<std::string> t{"foo"s};
+        // CHECK-FIXES: {{^        }}std::vector<std::string> u;
+        // CHECK-FIXES: {{^        }}std::vector<std::string> a({"hey", "you"});
+        // CHECK-FIXES: {{^        }}std::vector<std::string> bb = {"h", "a" };
+    }
+    
+    struct X { int a, b, c; };
+    auto [a, b, c] = X();
+}
+
Index: test/clang-tidy/readability-one-name-per-declaration-complex.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/readability-one-name-per-declaration-complex.cpp
@@ -0,0 +1,217 @@
+// RUN: %check_clang_tidy %s readability-one-name-per-declaration %t -- -- \
+// RUN:    -std=c++11
+
+void dontTouchParameter(int param1, int param2)
+{}
+
+int returner(void) 
+{
+    int f0 = 0, f1 = 1;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int f0 = 0;
+    // CHECK-FIXES: {{^    }}int f1 = 1;
+    
+    return 3;
+}
+
+struct StructOne 
+{
+    StructOne(){}
+    StructOne(int b){}
+    
+    int cantTouch1, cantTouch2;
+};
+
+using PointerType = int;
+
+struct TemT
+{
+    template<typename T>
+    T* getAs()
+    {
+        return nullptr;
+    }
+} TT1, TT2;
+
+void complex() 
+{
+    typedef int* IntPtr;
+    typedef int ArrayType[2];
+    typedef int FunType(void);
+    
+    IntPtr intptr1, intptr2 = nullptr, intptr3;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}IntPtr intptr1;
+    // CHECK-FIXES: {{^....}}IntPtr intptr2 = nullptr;
+    // CHECK-FIXES: {{^....}}IntPtr intptr3;
+    
+    ArrayType arraytype1, arraytype2 = {1}, arraytype3;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}ArrayType arraytype1;
+    // CHECK-FIXES: {{^....}}ArrayType arraytype2 = {1};
+    // CHECK-FIXES: {{^....}}ArrayType arraytype3;
+    
+    FunType funtype1, funtype2, functype3;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^....}}FunType funtype1;
+    // CHECK-FIXES: {{^....}}FunType funtype2;
+    // CHECK-FIXES: {{^....}}FunType functype3;
+    
+    for(int index1 = 0, index2 = 0;;)
+    {
+        int localFor1 = 1, localFor2 = 2;
+        // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+        // CHECK-FIXES: {{^        }}int localFor1 = 1;
+        // CHECK-FIXES: {{^        }}int localFor2 = 2;
+    }
+    
+    int v1, v2(3), v3, v4(4 ), v5{2}, v6 = {3};
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int v1;
+    // CHECK-FIXES: {{^    }}int v2(3);
+    // CHECK-FIXES: {{^    }}int v3;
+    // CHECK-FIXES: {{^    }}int v4(4 );
+    // CHECK-FIXES: {{^    }}int v5{2};
+    // CHECK-FIXES: {{^    }}int v6 = {3};
+    
+    StructOne s1, s2(23), s3, s4(3), *sptr = new StructOne(2);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}StructOne s1;
+    // CHECK-FIXES: {{^    }}StructOne s2(23);
+    // CHECK-FIXES: {{^    }}StructOne s3;
+    // CHECK-FIXES: {{^    }}StructOne s4(3);
+    // CHECK-FIXES: {{^    }}StructOne *sptr = new StructOne(2);
+    
+    struct StructOne cs1, cs2( 42 );
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}struct StructOne cs1;
+    // CHECK-FIXES: {{^    }}struct StructOne cs2( 42 );
+    
+    int *ptrArray[3], dummy, **ptrArray2[5], twoDim[2][3], *twoDimPtr[2][3];
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int *ptrArray[3];
+    // CHECK-FIXES: {{^    }}int dummy;
+    // CHECK-FIXES: {{^    }}int **ptrArray2[5];
+    // CHECK-FIXES: {{^    }}int twoDim[2][3];
+    // CHECK-FIXES: {{^    }}int *twoDimPtr[2][3];
+    
+        {
+            void f1(int), g1(int, float);
+            // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+            // CHECK-FIXES: {{^            }}void f1(int);
+            // CHECK-FIXES: {{^            }}void g1(int, float);
+        }
+
+        {
+            void gg(int, float);
+            
+            void ( *f2)(int), (*g2)(int, float) = gg;
+            // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+            // CHECK-FIXES: {{^            }}void ( *f2)(int);
+            // CHECK-FIXES: {{^            }}void (*g2)(int, float) = gg;
+            
+            void /*(*/ ( /*(*/ *f3)(int), (*g3)(int, float);
+            // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+            // CHECK-FIXES: {{^            }}void /*(*/ ( /*(*/ *f3)(int);
+            // CHECK-FIXES: {{^            }}void (*g3)(int, float);
+            
+        }
+    
+    struct S { int a; const int b; };
+    
+    int S::*p = &S::a, S::* const q = &S::a;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int S::*p = &S::a;
+    // CHECK-FIXES: {{^    }}int S::* const q = &S::a;
+    
+    int /* :: */ S::*pp2 = &S::a, var1 = 0;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int /* :: */ S::*pp2 = &S::a;
+    // CHECK-FIXES: {{^    }}int var1 = 0;
+    
+    const int S::*r = &S::b, S::*t;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int S::*r = &S::b;
+    // CHECK-FIXES: {{^    }}const int S::*t;
+    
+    typedef const int S::*MemPtr;
+    MemPtr aaa =  &S::a, bbb = &S::b;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}MemPtr aaa =  &S::a;
+    // CHECK-FIXES: {{^    }}MemPtr bbb = &S::b;
+    
+    class CS { public: int a; const int b; };
+    int const CS :: * pp = &CS::a, CS::* const qq = &CS::a;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int const CS :: * pp = &CS::a;
+    // CHECK-FIXES: {{^    }}int const CS::* const qq = &CS::a;
+    
+    int intfunction = returner(), intarray[] =
+          {
+                  1,
+                  2,
+                  3,
+                  4
+          }, bb = 4;
+    // CHECK-MESSAGES: :[[@LINE-7]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}int intfunction = returner();
+    // CHECK-FIXES: {{^    }}int intarray[] =
+    // CHECK-FIXES: {{^          }}{
+    // CHECK-FIXES: {{^                  }}1,
+    // CHECK-FIXES: {{^                  }}2,
+    // CHECK-FIXES: {{^                  }}3,
+    // CHECK-FIXES: {{^                  }}4
+    // CHECK-FIXES: {{^          }}};
+    // CHECK-FIXES: {{^    }}int bb = 4;
+    
+    TemT *T1 = &TT1, *T2 = &TT2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}TemT *T1 = &TT1;
+    // CHECK-FIXES: {{^    }}TemT *T2 = &TT2;
+
+    const PointerType *PT1 = T1->getAs<PointerType>(),
+                      *PT2 = T2->getAs<PointerType>();
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const PointerType *PT1 = T1->getAs<PointerType>();
+    // CHECK-FIXES: {{^    }}const PointerType *PT2 = T2->getAs<PointerType>();
+    
+    bool defPre = false,
+#ifdef IS_ENABLED
+       defTest = false;
+#else
+       defTest = true;
+#endif
+    // CHECK-MESSAGES: :[[@LINE-6]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}bool defPre = false;
+    // CHECK-FIXES: {{^    }}bool 
+    // CHECK-FIXES: {{^#}}ifdef IS_ENABLED
+    // CHECK-FIXES: {{^       }}defTest = false;
+    // CHECK-FIXES: {{^#}}else
+    // CHECK-FIXES: {{^       }}defTest = true;
+    // CHECK-FIXES: {{^#}}endif
+    
+    const int *p1 = nullptr;
+    const int *p2 = nullptr;
+    
+    const int *&pref1 = p1, *&pref2 = p2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}const int *&pref1 = p1;
+    // CHECK-FIXES: {{^    }}const int *&pref2 = p2;
+    
+    typedef int *tptr, tbt;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef int *tptr;
+    // CHECK-FIXES: {{^    }}typedef int tbt;
+    
+    typedef int (&tfp)(int, long), tarr[10];
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef int (&tfp)(int, long);
+    // CHECK-FIXES: {{^    }}typedef int tarr[10];
+    
+    typedef int tarr2[10], tct;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration statement can be split up into single line declarations [readability-one-name-per-declaration]
+    // CHECK-FIXES: {{^    }}typedef int tarr2[10];
+    // CHECK-FIXES: {{^    }}typedef int tct;
+
+}
+
Index: docs/clang-tidy/checks/readability-one-name-per-declaration.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/readability-one-name-per-declaration.rst
@@ -0,0 +1,59 @@
+.. title:: clang-tidy - readability-one-name-per-declaration
+
+readability-one-name-per-declaration
+====================================
+
+This check can be used to find declarations, which declare more than one name. 
+It helps improving readability and prevents potential bugs caused by inattention
+and C/C++ syntax specifics.
+
+In addition, appropriate fix-it hints are provided and all user-intended 
+indentation will be preserved. For example:
+
+.. code-block:: c++
+
+  {
+    long ** lint1, lint2 = 0, * lint3, **linn;
+  
+    const int cx = 1, cy = 2;
+  
+    int const CS :: * pp = &CS::a, CS::* const qq = &CS::a;
+  
+    decltype(int()) declint1 = 5, declint2 = 3;
+    
+    typedef int ta, tb;
+  }
+
+will be transformed to:
+
+.. code-block:: c++
+
+  {
+    long ** lint1;
+    long lint2 = 0;
+    long * lint3;
+    long **linn;
+    
+    const int cx = 1;
+    const int cy = 2;
+    
+    int const CS :: * pp = &CS::a;
+    int const CS::* const qq = &CS::a;
+    
+    decltype(int()) declint1 = 5;
+    decltype(int()) declint2 = 3;
+    
+    typedef int ta;
+    typedef int tb;
+  }
+
+Only declarations within a compound statement are matched. Meaning, global declarations
+and function parameters are not matched. Moreover, it does not match on the following:
+
+.. code-block:: c++
+
+  {
+    class A { } Object1, Object2;
+    
+    for(int i = 0, j = 0;;);
+  }
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -136,6 +136,7 @@
    readability-misplaced-array-index
    readability-named-parameter
    readability-non-const-parameter
+   readability-one-name-per-declaration
    readability-redundant-control-flow
    readability-redundant-declaration
    readability-redundant-member-init
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -136,6 +136,11 @@
   Flags function parameters of a pointer type that could be changed to point to
   a constant type instead.
 
+- New `readability-one-name-per-declaration
+  <http://clang.llvm.org/extra/clang-tidy/checks/readability-one-name-per-declaration.html>`_ check
+
+  Finds declarations declaring more that one name.
+
 - New `readability-redundant-declaration
   <http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-declaration.html>`_ check
 
Index: clang-tidy/utils/LexerUtils.h
===================================================================
--- clang-tidy/utils/LexerUtils.h
+++ clang-tidy/utils/LexerUtils.h
@@ -12,6 +12,7 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/Lex/Lexer.h"
+#include <vector>
 
 namespace clang {
 namespace tidy {
@@ -23,6 +24,13 @@
 Token getPreviousNonCommentToken(const ASTContext &Context,
                                  SourceLocation Location);
 
+/// \brief This function searches backward from the given location until
+/// TokenToFind is found. If the tokens is not found, the returned source
+/// location will be invalid.
+SourceLocation findTokenLocationBackward(const ASTContext &Context,
+                                         SourceLocation Location,
+                                         tok::TokenKind TokenToFind);
+
 } // namespace lexer
 } // namespace utils
 } // namespace tidy
Index: clang-tidy/utils/LexerUtils.cpp
===================================================================
--- clang-tidy/utils/LexerUtils.cpp
+++ clang-tidy/utils/LexerUtils.cpp
@@ -35,6 +35,27 @@
   return Token;
 }
 
+SourceLocation findTokenLocationBackward(const ASTContext &Context,
+                                         SourceLocation Location,
+                                         tok::TokenKind TokenToFind) {
+  const auto &SM = Context.getSourceManager();
+  const auto &LO = Context.getLangOpts();
+  auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location));
+
+  Token CurrentToken;
+  CurrentToken.setKind(tok::unknown);
+
+  while (Location != StartOfFile) {
+    if (!Lexer::getRawToken(Location, CurrentToken, SM, LO) &&
+        CurrentToken.is(TokenToFind)) {
+      return Location;
+    }
+    Location = Location.getLocWithOffset(-1);
+  }
+
+  return SourceLocation();
+}
+
 } // namespace lexer
 } // namespace utils
 } // namespace tidy
Index: clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -22,6 +22,7 @@
 #include "MisplacedArrayIndexCheck.h"
 #include "NamedParameterCheck.h"
 #include "NonConstParameterCheck.h"
+#include "OneNamePerDeclarationCheck.h"
 #include "RedundantControlFlowCheck.h"
 #include "RedundantDeclarationCheck.h"
 #include "RedundantMemberInitCheck.h"
@@ -59,6 +60,8 @@
         "readability-inconsistent-declaration-parameter-name");
     CheckFactories.registerCheck<MisplacedArrayIndexCheck>(
         "readability-misplaced-array-index");
+    CheckFactories.registerCheck<OneNamePerDeclarationCheck>(
+        "readability-one-name-per-declaration");
     CheckFactories.registerCheck<RedundantMemberInitCheck>(
         "readability-redundant-member-init");
     CheckFactories.registerCheck<StaticDefinitionInAnonymousNamespaceCheck>(
Index: clang-tidy/readability/OneNamePerDeclarationCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/readability/OneNamePerDeclarationCheck.h
@@ -0,0 +1,39 @@
+//===--- OneNamePerDeclarationCheck.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_READABILITY_ONE_NAME_PER_DECLARATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ONE_NAME_PER_DECLARATION_H
+
+#include "../ClangTidy.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks for declarations, declaring more than one name.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-one-name-per-declaration.html
+class OneNamePerDeclarationCheck : public ClangTidyCheck {
+private:
+  std::string getUserWrittenType(const DeclStmt *DeclStmt, SourceManager &SM);
+
+public:
+  OneNamePerDeclarationCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ONE_NAME_PER_DECLARATION_H
Index: clang-tidy/readability/OneNamePerDeclarationCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/readability/OneNamePerDeclarationCheck.cpp
@@ -0,0 +1,212 @@
+//===--- OneNamePerDeclarationCheck.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 "OneNamePerDeclarationCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+const internal::VariadicDynCastAllOfMatcher<Decl, TagDecl> tagDecl;
+
+static bool isWhitespaceExceptNL(unsigned char C);
+static std::string removeMultiLineComments(std::string Str);
+static std::string getCurrentLineIndent(SourceLocation Loc,
+                                        const SourceManager &SM);
+
+void OneNamePerDeclarationCheck::registerMatchers(MatchFinder *Finder) {
+
+  // Matches all non-single declaration within a compound statement {...}.
+  // Unless, the variable declaration is a object definition directly after
+  // a tag declaration (e.g. struct, class etc.):
+  // class A { } Object1, Object2;  <-- won't be matched
+  Finder->addMatcher(
+      declStmt(allOf(hasParent(compoundStmt()), hasDescendant(namedDecl()),
+                     unless(hasDescendant(tagDecl())), unless(declCountIs(1))))
+          .bind("declstmt"),
+      this);
+}
+
+void OneNamePerDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *DeclStatement = Result.Nodes.getNodeAs<DeclStmt>("declstmt");
+  if (DeclStatement == nullptr)
+    return;
+
+  // Macros will be ignored
+  if (DeclStatement->getLocStart().isMacroID())
+    return;
+
+  SourceManager &SM = *Result.SourceManager;
+  const LangOptions &LangOpts = getLangOpts();
+  const auto DeclGroup = DeclStatement->getDeclGroup();
+
+  const auto DeclStmtStart = DeclStatement->getLocStart();
+  const std::string CurrentIndent = getCurrentLineIndent(DeclStmtStart, SM);
+  const std::string UserWrittenType = getUserWrittenType(DeclStatement, SM);
+
+  auto Diag = diag(
+      DeclStmtStart,
+      "declaration statement can be split up into single line declarations");
+
+  // We will iterate through the declaration group starting with the second
+  // declaration. Then, the previous comma will be searched and replaced by a
+  // ';' and the UserWrittenType inserted after it.
+  for (auto It = DeclGroup.begin() + 1; It != DeclGroup.end(); ++It) {
+
+    const auto NameLocation = dyn_cast<const NamedDecl>(*It)->getLocation();
+    const auto CommaLocation = utils::lexer::findTokenLocationBackward(
+        *Result.Context, NameLocation, tok::comma);
+
+    if (CommaLocation.isValid()) {
+      const SourceRange AfterCommaToVarNameRange(
+          CommaLocation.getLocWithOffset(1), NameLocation);
+      std::string AnyTokenBetweenCommaAndVarName =
+          Lexer::getSourceText(
+              CharSourceRange::getTokenRange(AfterCommaToVarNameRange), SM,
+              LangOpts)
+              .ltrim(); // may be &, *, etc.
+
+      // Check for pre-processor directive and add appropriate newline
+      if (AnyTokenBetweenCommaAndVarName.front() == '#')
+        AnyTokenBetweenCommaAndVarName.insert(0, "\n");
+
+      Diag << FixItHint::CreateReplacement(CommaLocation, ";")
+           << FixItHint::CreateReplacement(AfterCommaToVarNameRange,
+                                           "\n" + CurrentIndent +
+                                               UserWrittenType + " " +
+                                               AnyTokenBetweenCommaAndVarName);
+    }
+  }
+}
+
+std::string
+OneNamePerDeclarationCheck::getUserWrittenType(const DeclStmt *DeclStmt,
+                                               SourceManager &SM) {
+  const auto FirstVarIt = DeclStmt->getDeclGroup().begin();
+
+  SourceLocation Location;
+  QualType Type;
+
+  if (const auto *FirstVar = dyn_cast<const DeclaratorDecl>(*FirstVarIt)) {
+    Location = FirstVar->getLocation();
+    Type = FirstVar->getType();
+  } else if (const auto *FirstVar = dyn_cast<const TypedefDecl>(*FirstVarIt)) {
+    Location = FirstVar->getLocation();
+    Type = FirstVar->getTypeSourceInfo()->getType();
+    if (Type->isLValueReferenceType()) {
+      Type = Type->getPointeeType();
+    }
+  } else {
+    llvm_unreachable(
+        "Declaration is neither a DeclaratorDecl nor a TypedefDecl");
+  }
+
+  const SourceRange FVLoc(DeclStmt->getLocStart(), Location);
+  std::string UserWrittenType =
+      Lexer::getSourceText(CharSourceRange::getCharRange(FVLoc), SM,
+                           getLangOpts())
+          .trim();
+
+  UserWrittenType = removeMultiLineComments(UserWrittenType);
+
+  // UserWrittenType might be and we want ->
+  // const int S::* -> const int
+  // const int *&   -> const int
+  // long **        -> long int
+
+  if (Type->isPointerType() || Type->isArrayType() || Type->isReferenceType() ||
+      Type->isFunctionPointerType() || Type->isFunctionProtoType()) {
+    const auto Pos = UserWrittenType.find_first_of("&*(");
+    if (Pos != std::string::npos) { // might be hidden behind typedef etc.
+      UserWrittenType.erase(Pos);
+      UserWrittenType = StringRef(UserWrittenType).trim();
+    }
+
+    return UserWrittenType;
+  }
+
+  if (const auto *MemberPointerT = Type->getAs<MemberPointerType>()) {
+    auto Pos = UserWrittenType.find("::");
+    if (Pos != std::string::npos) { // might be hidden behind typedef etc.
+
+      StringRef CN =
+          MemberPointerT->getClass()->getCanonicalTypeInternal().getAsString();
+
+      // CN will be 'struct/class Typename'. we are only interested in the
+      // second part
+      CN = CN.split(' ').second;
+      Pos = UserWrittenType.rfind(CN, Pos);
+      UserWrittenType.erase(Pos);
+      UserWrittenType = StringRef(UserWrittenType).trim();
+    }
+  }
+
+  return UserWrittenType;
+}
+
+static bool isWhitespaceExceptNL(unsigned char C) {
+  switch (C) {
+  case ' ':
+  case '\t':
+  case '\f':
+  case '\v':
+  case '\r':
+    return true;
+  default:
+    return false;
+  }
+}
+
+static std::string removeMultiLineComments(std::string Str) {
+  auto Pos1 = Str.find("/*");
+  while (Pos1 != std::string::npos) {
+    const auto Pos2 = Str.find("*/", Pos1 + 1);
+    Str.erase(Pos1, Pos2 - Pos1 + 2);
+    Pos1 = Str.find("/*");
+  }
+
+  Str = StringRef(Str).trim();
+  return Str;
+}
+
+static std::string getCurrentLineIndent(SourceLocation Loc,
+                                        const SourceManager &SM) {
+  const auto V = SM.getDecomposedLoc(Loc);
+  const FileID FID = V.first;
+  const unsigned StartOffs = V.second;
+
+  const StringRef MB = SM.getBufferData(FID);
+
+  const unsigned LineNo = SM.getLineNumber(FID, StartOffs) - 1;
+  const SrcMgr::ContentCache *Content =
+      SM.getSLocEntry(FID).getFile().getContentCache();
+  const unsigned LineOffs = Content->SourceLineCache[LineNo];
+
+  // Find the whitespace at the start of the line.
+  StringRef IndentSpace;
+  {
+    size_t i = LineOffs;
+    while (isWhitespaceExceptNL(MB[i])) {
+      ++i;
+    }
+    IndentSpace = MB.substr(LineOffs, i - LineOffs);
+  }
+
+  return IndentSpace;
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tidy/readability/CMakeLists.txt
+++ clang-tidy/readability/CMakeLists.txt
@@ -14,6 +14,7 @@
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp
   NonConstParameterCheck.cpp
+  OneNamePerDeclarationCheck.cpp
   ReadabilityTidyModule.cpp
   RedundantControlFlowCheck.cpp
   RedundantDeclarationCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to