Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
This revision was automatically updated to reflect the committed changes. Closed by commit rL279507: [clang-tidy] readability-non-const-parameter: add new check that warns when… (authored by danielmarjamaki). Changed prior to commit: https://reviews.llvm.org/D15332?vs=68531=68963#toc Repository: rL LLVM https://reviews.llvm.org/D15332 Files: clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.cpp clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.h clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp clang-tools-extra/trunk/docs/ReleaseNotes.rst clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst clang-tools-extra/trunk/docs/clang-tidy/checks/readability-non-const-parameter.rst clang-tools-extra/trunk/test/clang-tidy/readability-non-const-parameter.cpp Index: clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.h === --- clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.h +++ clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.h @@ -0,0 +1,64 @@ +//===--- NonConstParameterCheck.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_NON_CONST_PARAMETER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NON_CONST_PARAMETER_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Warn when a pointer function parameter can be const. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-non-const-parameter.html +class NonConstParameterCheck : public ClangTidyCheck { +public: + NonConstParameterCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult ) override; + void onEndOfTranslationUnit() override; + +private: + /// Parameter info. + struct ParmInfo { +/// Is function parameter referenced? +bool IsReferenced; + +/// Can function parameter be const? +bool CanBeConst; + }; + + /// Track all nonconst integer/float parameters. + std::map Parameters; + + /// Add function parameter. + void addParm(const ParmVarDecl *Parm); + + /// Set IsReferenced. + void setReferenced(const DeclRefExpr *Ref); + + /// Set CanNotBeConst. + /// Visits sub expressions recursively. If a DeclRefExpr is found + /// and CanNotBeConst is true the Parameter is marked as not-const. + /// The CanNotBeConst is updated as sub expressions are visited. + void markCanNotBeConst(const Expr *E, bool CanNotBeConst); + + /// Diagnose non const parameters. + void diagnoseNonConstParameters(); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NON_CONST_PARAMETER_H Index: clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp === --- clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -20,6 +20,7 @@ #include "ImplicitBoolCastCheck.h" #include "InconsistentDeclarationParameterNameCheck.h" #include "NamedParameterCheck.h" +#include "NonConstParameterCheck.h" #include "RedundantControlFlowCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" @@ -57,6 +58,8 @@ "readability-static-definition-in-anonymous-namespace"); CheckFactories.registerCheck( "readability-named-parameter"); +CheckFactories.registerCheck( +"readability-non-const-parameter"); CheckFactories.registerCheck( "readability-redundant-control-flow"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/readability/NonConstParameterCheck.cpp @@ -0,0 +1,214 @@ +//===--- NonConstParameterCheck.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
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
alexfh accepted this revision. alexfh added a comment. This revision is now accepted and ready to land. LG Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:104 @@ +103,3 @@ + const QualType T = Parm->getType(); + if (!T->isPointerType() || T->getPointeeType().isConstQualified() || + !(T->getPointeeType()->isIntegerType() || You're right. I was thinking about enums, but `isIntegerType` takes care of them too. As the next step, we should try to add all POD types, but that's a question for another patch. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:118-136 @@ +117,21 @@ +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; `PointerParameterConstnessCheck` is not much better, IMO. Maybe `readability-use-pointer-to-const-parameter`? Or just leave it like this for now. https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 68531. danielmarjamaki added a comment. Fixed review comments about formatting in doc https://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/ReleaseNotes.rst docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,279 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(); } + +typedef union { void *v; } t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + +void f8(int ); +void callFunction8(int *p) { + f8(*p); +} +
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 68528. danielmarjamaki marked 2 inline comments as done. danielmarjamaki added a comment. Fixed review comments https://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/ReleaseNotes.rst docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,279 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(); } + +typedef union { void *v; } t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + +void f8(int ); +void
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 6 inline comments as done. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:95-98 @@ +94,6 @@ +const QualType T = VD->getType(); +if (T->isPointerType() && !T->getPointeeType().isConstQualified()) + markCanNotBeConst(VD->getInit(), true); +else if (T->isArrayType()) + markCanNotBeConst(VD->getInit(), true); + } alexfh wrote: > danielmarjamaki wrote: > > Prazek wrote: > > > This looks like it could be in the same if. > > Yes it could. But would it make the code more or less readable? It wouldn't > > be a 1-line condition anymore then. > I also think that it makes sense to merge the conditions. The problem with > the current code is that it is suspicious ("Why is the same action is done in > two branches? Is it a bug?"). One line condition vs two lines seems secondary > in this case. ok Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:103 @@ +102,3 @@ +void NonConstParameterCheck::addParm(const ParmVarDecl *Parm) { + // Only add nonconst integer/float pointer parameters. + const QualType T = Parm->getType(); alexfh wrote: > This seems too strict. What about other primitive types? I am not sure which type you are talking about. As far as I see we're writing warnings about bool,char,short,int,long,long long,float,double,long double,enum pointers. I have intentionally avoided records now to start with. It should be added, but we need to be more careful when we do it. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:210 @@ +209,3 @@ +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +int functionpointer2(int *p) +{ alexfh wrote: > Put braces on the previous line, please. A few other instances below. sorry .. of course I should run clang-format on this. https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
alexfh requested changes to this revision. This revision now requires changes to proceed. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:95-98 @@ +94,6 @@ +const QualType T = VD->getType(); +if (T->isPointerType() && !T->getPointeeType().isConstQualified()) + markCanNotBeConst(VD->getInit(), true); +else if (T->isArrayType()) + markCanNotBeConst(VD->getInit(), true); + } danielmarjamaki wrote: > Prazek wrote: > > This looks like it could be in the same if. > Yes it could. But would it make the code more or less readable? It wouldn't > be a 1-line condition anymore then. I also think that it makes sense to merge the conditions. The problem with the current code is that it is suspicious ("Why is the same action is done in two branches? Is it a bug?"). One line condition vs two lines seems secondary in this case. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:103 @@ +102,3 @@ +void NonConstParameterCheck::addParm(const ParmVarDecl *Parm) { + // Only add nonconst integer/float pointer parameters. + const QualType T = Parm->getType(); This seems too strict. What about other primitive types? Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:22 @@ +21,3 @@ + // interface safer. + char f1(char *p) + { Please put braces on the same line with the function header. We should keep documentation consistent with LLVM style (where there's no good reason to do otherwise). Comment at: test/clang-tidy/readability-non-const-parameter.cpp:210 @@ +209,3 @@ +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +int functionpointer2(int *p) +{ Put braces on the previous line, please. A few other instances below. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:238 @@ +237,3 @@ + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be + C2(int *p) : p(p) {} +private: Add a CHECK-FIXES, please. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:253 @@ +252,3 @@ +class Warn { +public: + // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be Clang-tidy can't yet analyze multiple translation units simultaneously, so we just need to keep cases that can't be correctly handled by analyzing a single translation unit at a time in mind (and also in documentation and in tests), so that they are less surprising to the user. However, the check can and should take care of correctly handling this case in a single translation unit (as in this test, `use_functionpointer2`). I'm not sure it's a frequent case, so I don't insist on fixing this right away. May be fine for a follow up. https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki added inline comments. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:95-98 @@ +94,6 @@ +const QualType T = VD->getType(); +if (T->isPointerType() && !T->getPointeeType().isConstQualified()) + markCanNotBeConst(VD->getInit(), true); +else if (T->isArrayType()) + markCanNotBeConst(VD->getInit(), true); + } Prazek wrote: > This looks like it could be in the same if. Yes it could. But would it make the code more or less readable? It wouldn't be a 1-line condition anymore then. https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
Prazek added a subscriber: Prazek. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:95-98 @@ +94,6 @@ +const QualType T = VD->getType(); +if (T->isPointerType() && !T->getPointeeType().isConstQualified()) + markCanNotBeConst(VD->getInit(), true); +else if (T->isArrayType()) + markCanNotBeConst(VD->getInit(), true); + } This looks like it could be in the same if. https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 2 inline comments as done. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:245 @@ +244,3 @@ + C c(p); +} + I have added tests and fixed FPs in latest diff. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:252 @@ +251,3 @@ + +class Warn { +public: I have added a test in latest diff. but there is a false positive. I believe I heard about whole program analysis in clang-tidy sometime.. is that something worked on / implemented yet? https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 67504. danielmarjamaki added a comment. fixed more review comments https://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,283 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(); } + +typedef union { void *v; } t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + +void f8(int ); +void callFunction8(int *p) { + f8(*p); +} + +// Don't warn about nonconst function
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 10 inline comments as done. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:117-135 @@ +116,21 @@ +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} I have changed the message now. pointer parameter 'p' can be pointer to const The name is the same. Do you think it would be better with PointerParameterConstnessCheck() perhaps? https://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 67500. danielmarjamaki added a comment. Fix patch so it can be applied in latest trunk. Tried to fix review comments. https://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,251 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(); } + +typedef union { void *v; } t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + +void f8(int ); +void callFunction8(int *p) { +
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
Eugene.Zelenko added a comment. Please also mention check in docs/ReleaseNotes.rst. Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:15 @@ +14,3 @@ + + // warning here; the declaration "const char *p" would make the function + // interface safer. I think you should add ".. code-block:: c++" before code block. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
alexfh added inline comments. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:44 @@ +43,3 @@ +addParm(Parm); + } else if (const CXXConstructorDecl *Ctor = + Result.Nodes.getNodeAs("Ctor")) { `const auto *Ctor` Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:7 @@ +6,3 @@ +Finds function pointer parameters that should be const. When const is used +properly, many mistakes can be avoided. Advantages when using const properly: + * avoid that data is unintentionally modified That now sounds ambiguous (is it about parameters of a pointer to a function type?). I'd say "The check finds function parameters of a pointer type that could be changed to point to a constant type instead." or something similar. Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:8 @@ +7,3 @@ +properly, many mistakes can be avoided. Advantages when using const properly: + * avoid that data is unintentionally modified + * get additional warnings such as using uninitialized data "prevent unintentional modification of data" Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:10 @@ +9,3 @@ + * get additional warnings such as using uninitialized data + * easier for developers to see possible side effects + "make it easier for developers ..." Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:12 @@ +11,3 @@ + +clang-tidy is not strict about constness, it only warns when the constness will +make the function interface safer. s/clang-tidy/This check/ Comment at: test/clang-tidy/readability-non-const-parameter.cpp:244 @@ +243,3 @@ + // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: parameter 'p' can be const + void doStuff(int *p) { + // CHECK-FIXES: {{^}} void doStuff(const int *p) {{{$}} Please add a test to ensure that overridden methods are not modified (since you would need to update the base class' method and then all the other overrides. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:251 @@ +250,2 @@ +}; + The check can break code taking a pointer to a function it modifies: typedef int (*fn)(int *); int f(int *p) {return *p; } fn fp = It's not always possible to detect, when this happens (for example, a pointer to the function could be taken in a different translation unit), but we should at least keep this case in mind. Please add a test case for this. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
LegalizeAdulthood added inline comments. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:116-134 @@ +115,21 @@ + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const +const char *return4(char *p) { danielmarjamaki wrote: > rsmith wrote: > > The wording of this warning, and the name of the check, are highly > > misleading. > > > > It's *not* the parameter that can be const, it's the parameter's *pointee*. > I understand. Figuring out a better message is not easy. I and a collegue > brain stormed: > > pointer parameter 'p' could be declared with const 'const int *p' > > pointer parameter 'p' could be pointer to const > > pointer parameter 'p' declaration could be pointer to const > > missing const in pointer parameter 'p' declaration > > declaration of pointer parameter 'p' could be 'const int *p' > > Do you think any of these would be good? > Regarding the name of the check, I can't think of anything better only things that are longer but aren't substantially more clear in revealing the intent of the check. IMO, you don't blindly run clang-tidy checks based on the name, you run them after reading what they do and deciding if you want that transformation or not. In order of my preference: - pointer parameter 'p' could be pointer to const - declaration of pointer parameter 'p' could be 'const int *p' I might use the word 'can' instead of the world 'could', but that's a very minor quibble. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
rsmith added inline comments. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:116-134 @@ +115,21 @@ + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const +const char *return4(char *p) { The wording of this warning, and the name of the check, are highly misleading. It's *not* the parameter that can be const, it's the parameter's *pointee*. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 50705. danielmarjamaki marked 3 inline comments as done. danielmarjamaki added a comment. Fixed review comments http://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,251 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(); } + +typedef union { void *v; } t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + +void f8(int ); +void callFunction8(int *p) { + f8(*p); +} + +// Don't warn about nonconst
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 12 inline comments as done. Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:6 @@ +5,3 @@ + +Finds function parameters that should be const. When const is used properly, +many mistakes can be avoided. Advantages when using const properly: hokein wrote: > Looks like what the document says isn't consistent with the check, since the > check only finds non-const pointer parameter. I changed "Finds function parameters.." to "Finds function pointer parameters..". Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 @@ +2,3 @@ + +// Currently the checker only warns about pointer arguments. +// hokein wrote: > It makes sense to move this document to the `rst`, I think. Done. First line in rst will now say: "Finds function pointer parameters that should be const". Comment at: test/clang-tidy/readability-non-const-parameter.cpp:219 @@ +218,3 @@ +public: + C(int *p) : p(p) {} +private: hokein wrote: > Please add a test case: > > ``` > class C { > public: > C(int *p) : p(p) {} > private: > const int *p; > }; > ``` > > BTW, does the check support class method? Thanks, I added such class. I also added one class that shows that class methods are supported. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
hokein added inline comments. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:24 @@ +23,3 @@ + + // C++ constructor.. + Finder->addMatcher(cxxConstructorDecl().bind("Ctor"), this); Extra `.` at the end. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:124 @@ +123,3 @@ +void NonConstParameterCheck::diagnoseNonConstParameters() { + for (auto It : Parameters) { +const ParmVarDecl *Par = It.first; const auto Comment at: clang-tidy/readability/NonConstParameterCheck.h:53 @@ +52,3 @@ + /// and CanNotBeConst is true the Parameter is marked as not-const. + /// The CanNotBeConst are updated as sub expressions are visited. + void markCanNotBeConst(const Expr *E, bool CanNotBeConst); s/are/is Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:6 @@ +5,3 @@ + +Finds function parameters that should be const. When const is used properly, +many mistakes can be avoided. Advantages when using const properly: Looks like what the document says isn't consistent with the check, since the check only finds non-const pointer parameter. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 @@ +2,3 @@ + +// Currently the checker only warns about pointer arguments. +// It makes sense to move this document to the `rst`, I think. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:15 @@ +14,3 @@ + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { Just keep the whole warning message in the first CHECK-MESSAGE. And remove `[readability-non-const-parameter]` in others CHECK-MESSAGE for keeping the line short. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:219 @@ +218,3 @@ +public: + C(int *p) : p(p) {} +private: Please add a test case: ``` class C { public: C(int *p) : p(p) {} private: const int *p; }; ``` BTW, does the check support class method? http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki added a comment. ping. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 50032. danielmarjamaki added a comment. Updated documentation http://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,231 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const [readability-non-const-parameter] +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const [readability-non-const-parameter] +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki added inline comments. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 @@ +2,3 @@ + +// Currently the checker only warns about pointer arguments. +// LegalizeAdulthood wrote: > danielmarjamaki wrote: > > LegalizeAdulthood wrote: > > > How hard is it to extend it to references? > > > > > > Certainly the confusion about what is const is easier to resolve in the > > > case of references because the references themselves are immutable. > > If a "int &" reference parameter is not written then probably it's better > > to pass it by value than making it const. I would prefer that unless it has > > to use "int &" to comply with some interface. > > > > I realize that the same can be said about pointers. If there is a "int *p" > > and you just read the value that p points at .. maybe sometimes it would be > > preferable to pass it by value. > I thought the point of this check was to identify stuff passed by > reference/pointer that could instead be passed by const reference/pointer. > > Passing a read-only number type (`short`, `char`, `int`, `float`, `double`, > etc.) parameter by pointer or by reference/pointer is a code smell, but this > check isn't trying to identify that situation. > > I'm more interested in things like: > > ``` > void foo(std::string ); > ``` > > becoming > > ``` > void foo(const std::string ); > ``` > > when `s` is treated as a read-only value within the implementation of `foo`. I agree pointers and references are related from user perspective. But technically I think we can't reuse the same markCanNotBeConst code. This expression "p += 2" does not prevent that *p is const. But "r += 2" would prevent that the reference r is const. > I'm more interested in things like: Yes that would be interesting. However I only warn about number types right now. As my last example in the rst file shows I don't warn for non-constant struct pointers for a reason. Imho, I would like to have a warning when the data is modified even though *p is const. Like this: struct S { int *a; int *b; }; int f3(const struct S * const p) { *(p->a) = 0; // <- I would like to have warning here } Also dealing with C++ is not my priority. I write this check so I can use it on C code. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
LegalizeAdulthood added inline comments. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 @@ +2,3 @@ + +// Currently the checker only warns about pointer arguments. +// danielmarjamaki wrote: > LegalizeAdulthood wrote: > > How hard is it to extend it to references? > > > > Certainly the confusion about what is const is easier to resolve in the > > case of references because the references themselves are immutable. > If a "int &" reference parameter is not written then probably it's better to > pass it by value than making it const. I would prefer that unless it has to > use "int &" to comply with some interface. > > I realize that the same can be said about pointers. If there is a "int *p" > and you just read the value that p points at .. maybe sometimes it would be > preferable to pass it by value. I thought the point of this check was to identify stuff passed by reference/pointer that could instead be passed by const reference/pointer. Passing a read-only number type (`short`, `char`, `int`, `float`, `double`, etc.) parameter by pointer or by reference/pointer is a code smell, but this check isn't trying to identify that situation. I'm more interested in things like: ``` void foo(std::string ); ``` becoming ``` void foo(const std::string ); ``` when `s` is treated as a read-only value within the implementation of `foo`. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
On Wed, Feb 17, 2016 at 2:39 AM, Daniel Marjamäkiwrote: > danielmarjamaki marked 2 inline comments as done. > > > Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:15 > @@ +14,3 @@ > + > + // warning here; p should be const > + char f1(char *p) { > > LegalizeAdulthood wrote: >> With pointers, there are always two layers of constness: >> >> >> - Whether the pointer itself is modified >> - Whether the data pointed to is modified >> >> When you say "p should be const", I read that as the former. >> >> I am pretty sure you intended the latter. You should be more explicit in >> your documentation. The ambiguity would have been resolved if you showed >> the "after" version of the code that would eliminate the warning. This is >> semi-implied by your next example, but it's kinder to the reader to resolve >> this ambiguity immediately. >> >> > ok I understand, will try to improve > > > Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 > @@ +2,3 @@ > + > +// Currently the checker only warns about pointer arguments. > +// > > LegalizeAdulthood wrote: >> How hard is it to extend it to references? >> >> Certainly the confusion about what is const is easier to resolve in the case >> of references because the references themselves are immutable. > If a "int &" reference parameter is not written then probably it's better to > pass it by value than making it const. I would prefer that unless it has to > use "int &" to comply with some interface. I think it makes sense to pass it by value only if it is not an expensive-to-copy type (we have an AST matcher helper for that in TypeTraits.h), or to comply with an interface. ~Aaron > > I realize that the same can be said about pointers. If there is a "int *p" > and you just read the value that p points at .. maybe sometimes it would be > preferable to pass it by value. > > > http://reviews.llvm.org/D15332 > > > ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
LegalizeAdulthood added inline comments. Comment at: test/clang-tidy/readability-non-const-parameter.cpp:3 @@ +2,3 @@ + +// Currently the checker only warns about pointer arguments. +// How hard is it to extend it to references? Certainly the confusion about what is const is easier to resolve in the case of references because the references themselves are immutable. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
LegalizeAdulthood added a subscriber: LegalizeAdulthood. Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:15 @@ +14,3 @@ + + // warning here; p should be const + char f1(char *p) { With pointers, there are always two layers of constness: - Whether the pointer itself is modified - Whether the data pointed to is modified When you say "p should be const", I read that as the former. I am pretty sure you intended the latter. You should be more explicit in your documentation. The ambiguity would have been resolved if you showed the "after" version of the code that would eliminate the warning. This is semi-implied by your next example, but it's kinder to the reader to resolve this ambiguity immediately. Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:32 @@ +31,3 @@ + // no warning; Technically, p can be const ("const struct S *p"). But making + // p const could be misleading. People might think that it's safe to pass + // const data to this function. Here you are using "making p const" in the first sense I noted above. It might help if you say "make `*p` const" when you mean that p points to constant data and use "making `p` const" when you mean that the pointer itself is unmodified. There is also the wart in C++ that one can declare a function like this: ``` int f(char *p); ``` and define it like this: ``` int f(char *const p) { // ... } ``` My sense is that this is pretty confusing to most programmers who really want the declaration and definition to be textually identical. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki added a comment. In http://reviews.llvm.org/D15332#352556, @danielmarjamaki wrote: > > I see no warning when running on Clang source code (files in > llvm/tools/clang/lib/...). For information I rerun with --header-filter=* and got some results.. I will triage those.. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 47962. danielmarjamaki added a comment. Run this check on C++ code also. I have rerun the add_new_check python script. Minor code cleanups. I have run this on the debian packages again. In 1806 projects there were 9691 warnings. I have so far triaged 51 of those warnings and they were all true positives as far as I saw. I see no warning when running on Clang source code (files in llvm/tools/clang/lib/...). http://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,231 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const [readability-non-const-parameter] +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const [readability-non-const-parameter] +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +void dontwarn2(int *p) { + (*p)++; +} + +int dontwarn3(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { +
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 12 inline comments as done. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:44 @@ +43,3 @@ + if (B->isAssignmentOp()) +markCanNotBeConst(B, false); +} else if (const auto *CE = dyn_cast(S)) { I tried to unify like that. It almost worked. I failed to put the stmt(...) and varDecl(...) in the same matcher. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:49 @@ +48,3 @@ + for (const auto *Arg : CE->arguments()) { +markCanNotBeConst(Arg->IgnoreParenCasts(), true); + } good question! I tested and the checker seemed to handle these. apparently the ast-matcher scanned the functions recursively. However I don't know if we know that it will work, so I changed the checker. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:84 @@ +83,3 @@ +} + +void NonConstParameterCheck::onEndOfTranslationUnit() { I believe I fixed all these. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki updated this revision to Diff 42292. danielmarjamaki added a comment. I have tried to fix the comments. This patch is mostly untested. I have only run 'make check-all'. I am running more tests right now. http://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.cpp Index: test/clang-tidy/readability-non-const-parameter.cpp === --- test/clang-tidy/readability-non-const-parameter.cpp +++ test/clang-tidy/readability-non-const-parameter.cpp @@ -0,0 +1,211 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char *strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { + // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) { + } // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign1(int *p) { + // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign2(int *p) { + // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) { + } +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i < 10; i++, p++) { +*p = 1; + } +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init1(int *p) { + // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init2(int *p) { + // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p, p, 0}; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++) +; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const [readability-non-const-parameter] +int return1(int *p) { + // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return2(int *p) { + // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return3(int *p) { + // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const [readability-non-const-parameter] +const char *return4(char *p) { + // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + +void dontwarn1(int *p) { + ++(*p); +} + +int dontwarn2(_Atomic(int) * p) { + return *p; +} + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1([0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p + 2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); +
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
alexfh added a comment. Please add tests with templates and macros. Please also run this on LLVM/Clang to ensure a) it doesn't crash; b) the number of warnings is sane; c) a representative sample of warnings doesn't contain false positives. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki marked 3 inline comments as done. danielmarjamaki added a comment. In http://reviews.llvm.org/D15332#305976, @alexfh wrote: > Please add tests with templates and macros. Please also run this on > LLVM/Clang to ensure a) it doesn't crash; b) the number of warnings is sane; > c) a representative sample of warnings doesn't contain false positives. I am running clang-tidy on LLVM/Clang right now. I expect that it will take several hours. I expect that I will get false positives when there are templates and I will add corresponding test cases. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
Eugene.Zelenko added a subscriber: Eugene.Zelenko. Eugene.Zelenko added a comment. This check partially implements PR19419. Could it be extended to variables? http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki added a comment. In http://reviews.llvm.org/D15332#306097, @Eugene.Zelenko wrote: > This check partially implements PR19419. Could it be extended to variables? Yes, I don't see any technical reasons why that would not work. However politically, some people like const variables and others don't. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D15332: new clang-tidy checker readability-non-const-parameter
danielmarjamaki created this revision. danielmarjamaki added reviewers: alexfh, aaron.ballman, rsmith. danielmarjamaki added subscribers: cfe-commits, sberg. This is a new clang-tidy checker that will warn when function parameters should be const. See also related discussions in http://reviews.llvm.org/D12359 As usual, I am testing this checker on the debian projects. I have so far triaged 20 warnings from this clang-tidy checker and they were all true positives. http://reviews.llvm.org/D15332 Files: clang-tidy/readability/CMakeLists.txt clang-tidy/readability/NonConstParameterCheck.cpp clang-tidy/readability/NonConstParameterCheck.h clang-tidy/readability/ReadabilityTidyModule.cpp docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/readability-non-const-parameter.rst test/clang-tidy/readability-non-const-parameter.c Index: test/clang-tidy/readability-non-const-parameter.c === --- test/clang-tidy/readability-non-const-parameter.c +++ test/clang-tidy/readability-non-const-parameter.c @@ -0,0 +1,215 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +// Currently the checker only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the checker only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char* strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + + +// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: parameter 'last' can be const [readability-non-const-parameter] +void warn1(int *first, int *last) { +// CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} + *first = 0; + if (first < last) {} // <- last can be const +} + +// TODO: warning should be written here +void warn2(char *p) { + char buf[10]; + strcpy1(buf, p); +} + + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign1(int *p) { +// CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} + const int *q; + q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: parameter 'p' can be const [readability-non-const-parameter] +void assign2(int *p) { +// CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(int *p) { + *p += 2; +} + +void assign5(char *p) { + p[0] = 0; +} + +void assign6(int *p) { + int *q; + q = p++; +} + +void assign7(char *p) { + char *a, *b; + a = b = p; +} + +void assign8(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign9(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p;) {} +} + +void assign10(int *buf) { + int i, *p; + for (i = 0, p = buf; i<10; i++, p++) { +*p = 1; + } +} + + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init1(int *p) { +// CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} + const int *q = p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: parameter 'p' can be const [readability-non-const-parameter] +void init2(int *p) { +// CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = { p, p, 0 }; +} + +void init7(int *p, int x) { + for (int *q = p + x - 1; 0; q++); +} + + +// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: parameter 'p' can be const [readability-non-const-parameter] +int return1(int *p) { +// CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} + return *p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return2(int *p) { +// CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} + return p; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: parameter 'p' can be const [readability-non-const-parameter] +const int *return3(int *p) { +// CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} + return p + 1; +} + +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: parameter 'p' can be const [readability-non-const-parameter] +const char *return4(char *p) { +// CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s + 1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + + +void dontwarn1(int *p) { + ++(*p); +} + +int dontwarn2(_Atomic(int) *p) { + return *p; +} + + + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { +
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
alexfh added inline comments. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:20 @@ +19,3 @@ +void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) { + // TODO: This checker doesn't handle C++ to start with. There are problems + // for example with parameters to template functions. I'd prefer the problem to be fixed right away instead of disabling this check for C++. The specific issue of parameters of template functions can probably be addressed by disabling matches in template instantiations (add `unless(isInTemplateInstantiation())` or `unless(isInstantiated())` depending on what kind of node is being matched). Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:83 @@ +82,3 @@ +void NonConstParameterCheck::ref(const DeclRefExpr *Ref) { + struct ParInfo *PI = getParInfo(Ref->getDecl()); + if (PI) Use the `if (T *x = ...) {...}` pattern, please. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:89 @@ +88,3 @@ +struct ParInfo *NonConstParameterCheck::getParInfo(const Decl *D) { + for (struct ParInfo : Params) { +if (ParamInfo.Par == D) aaron.ballman wrote: > This loop can be replaced with std::find_if(). While I agree with similar comments in general, it seems that here it wouldn't make the code any better. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:168 @@ +167,3 @@ + if (auto *Par = dyn_cast(D->getDecl())) { +struct ParInfo *PI = getParInfo(Par); +if (PI) `if (ParInfo *PI = ...) ...` Comment at: docs/clang-tidy/checks/readability-non-const-parameter.rst:14 @@ +13,3 @@ + // warning here; p should be const + char f1(char *p) + { Let's format the code examples in LLVM style. Comment at: test/clang-tidy/readability-non-const-parameter.c:211 @@ +210,3 @@ +// avoid fp for const pointer array +void constPointerArray(const char *remapped[][2]) +{ clang-format? http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D15332: new clang-tidy checker readability-non-const-parameter
aaron.ballman added inline comments. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:43 @@ +42,3 @@ + Finder->addMatcher(returnStmt().bind("return"), this); +} + I think it may be an improvement to unify all of the matchers that will eventually be used to call markCanNotBeConst() from check() into a single matcher. e.g., ``` Finder->addMatcher( anyOf(stmt(anyOf(binaryOperator(...), callExpr(), returnStmt(), unaryOperator(...))).bind("mark"), varDecl(...).bind("mark")), this); ``` The implementation of check() won't have to change too much, but this reduces the number of individual matchers required which I think may be a performance win (gut feeling, not based on evidence) and does not reduce clarity. Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:48 @@ +47,3 @@ +diagnoseNonConstParameters(); +Params.clear(); + } else if (auto *Par = Result.Nodes.getNodeAs("par")) { What will this do with code like: ``` int f(int *p) { void g(); return *p; } ``` or ``` int f(int *p) { struct S { void g(); }; return *p; } ``` Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:63 @@ +62,3 @@ + } else if (auto *CE = Result.Nodes.getNodeAs("call")) { +// TODO: Handle function calls better +for (auto *Arg : CE->arguments()) { Better how? Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:89 @@ +88,3 @@ +struct ParInfo *NonConstParameterCheck::getParInfo(const Decl *D) { + for (struct ParInfo : Params) { +if (ParamInfo.Par == D) This loop can be replaced with std::find_if(). Comment at: clang-tidy/readability/NonConstParameterCheck.cpp:124 @@ +123,3 @@ +void NonConstParameterCheck::markCanNotBeConst(const Expr *E, bool Addr) { + if (auto *Cast = dyn_cast(E)) { +// If expression is const then ignore usage. These should all be const auto * because E is a const Expr *. Comment at: clang-tidy/readability/NonConstParameterCheck.h:19 @@ +18,3 @@ + +struct ParInfo { + /// Function parameter I think this struct can be local to NonConstParameterCheck. Comment at: clang-tidy/readability/NonConstParameterCheck.h:43 @@ +42,3 @@ +private: + SmallVector Params; + void addPar(const ParmVarDecl *Par); No need for the struct keyword, here and elsewhere. Comment at: clang-tidy/readability/NonConstParameterCheck.h:44 @@ +43,3 @@ + SmallVector Params; + void addPar(const ParmVarDecl *Par); + void ref(const DeclRefExpr *Ref); addParm instead of addPar, for clarity? Comment at: clang-tidy/readability/NonConstParameterCheck.h:45 @@ +44,3 @@ + void addPar(const ParmVarDecl *Par); + void ref(const DeclRefExpr *Ref); + void markCanNotBeConst(const Expr *E, bool Addr); I haven't gotten to the function definition yet, but I have no idea what this function would do. ;-) A more clear identifier would be appreciated. http://reviews.llvm.org/D15332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits