Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom clang tidy plugin #30886

Merged
merged 28 commits into from
Jun 20, 2019
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
720823a
Don't use CMake option command for non-booleans
jbytheway May 24, 2019
b0a8a50
Initial version of a no-long check
jbytheway May 24, 2019
53d0233
Enable cata checks in clang-tidy
jbytheway May 24, 2019
3b73b6f
Try to support building and running on Travis
jbytheway May 26, 2019
8f5cb00
build.sh: Replace a 3 with $num_jobs
jbytheway May 26, 2019
91946b2
Configure Travis to run clang-tidy plugin
jbytheway May 26, 2019
5c72b74
Add tests for NoLongCheck
jbytheway May 27, 2019
41f4086
Use CMake option rather than env var
jbytheway May 28, 2019
fa8f41f
Add some docs regarding how to use the plugin
jbytheway May 28, 2019
8c9108e
Also catch unsigned long in cata-no-long check
jbytheway Jun 8, 2019
85a1907
More tests for cata-no-long check
jbytheway Jun 8, 2019
85d7b9f
Check function return types are not long
jbytheway Jun 8, 2019
65ac6f8
Tweak function tests for cata-no-long
jbytheway Jun 8, 2019
6b8be84
Check for static_cast<long> in cata-no-long
jbytheway Jun 8, 2019
d688b0d
cata-no-long: Handle qualified and reference types
jbytheway Jun 8, 2019
adc3f21
Astyle clang-tidy plugin code
jbytheway Jun 9, 2019
30287ab
Enforce astyle on clang-tidy plugin code
jbytheway Jun 9, 2019
9eb11d1
Avoid some false positives in cata-no-long check
jbytheway Jun 10, 2019
dce24e5
NoLongCheck now tests for long-specific macros
jbytheway Jun 10, 2019
10c463b
Avoid false-positives on return values
jbytheway Jun 11, 2019
037c250
Avoid false positives on deduced return types
jbytheway Jun 11, 2019
a30b6fe
Change naming convention in NoLongCheck test
jbytheway Jun 12, 2019
8fe1cda
Avoid false-positives on deduced variable types
jbytheway Jun 12, 2019
cef5be2
cata-no-long: Avoid false-positives on auto&
jbytheway Jun 13, 2019
9cce062
Avoid false positive on autogenerated code
jbytheway Jun 13, 2019
63e5e1e
Avoid false-positives on templated return types
jbytheway Jun 14, 2019
ac2ec51
Mention size_t as an alternative to unsigned int
jbytheway Jun 19, 2019
2d801ea
Fix a couple of casts to unsigned long
jbytheway Jun 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cata-no-long: Handle qualified and reference types
Previously we would not flag uses of long if cv-qualified or a reference
type.  Now we will.
jbytheway committed Jun 19, 2019
commit d688b0d53b36b2f54e7756def31537ed34e6586b
68 changes: 37 additions & 31 deletions tools/clang-tidy-plugin/NoLongCheck.cpp
Original file line number Diff line number Diff line change
@@ -10,61 +10,67 @@ namespace cata {

void NoLongCheck::registerMatchers(MatchFinder *Finder) {
using TypeMatcher = clang::ast_matchers::internal::Matcher<QualType>;
const TypeMatcher isLong = anyOf(asString("long"), asString("unsigned long"));
Finder->addMatcher(valueDecl(hasType(isLong)).bind("decl"), this);
Finder->addMatcher(functionDecl(returns(isLong)).bind("return"), this);
Finder->addMatcher(cxxStaticCastExpr(hasType(isLong)).bind("cast"), this);
const TypeMatcher isIntegerOrRef = anyOf(isInteger(), references(isInteger()));
Finder->addMatcher(valueDecl(hasType(isIntegerOrRef)).bind("decl"), this);
Finder->addMatcher(functionDecl(returns(isIntegerOrRef)).bind("return"), this);
Finder->addMatcher(cxxStaticCastExpr(hasDestinationType(isIntegerOrRef)).bind("cast"), this);
}

static std::string AlternativesFor( QualType Type ) {
Type = Type.getNonReferenceType();
Type = Type.getLocalUnqualifiedType();
std::string name = Type.getAsString();
if( name == "long" ) {
return "Prefer int or int64_t to long";
} else if( name == "unsigned long" ) {
return "Prefer unsigned int or uint64_t to unsigned long";
} else {
return {};
}
}

static void CheckDecl(NoLongCheck &Check, const MatchFinder::MatchResult &Result) {
const ValueDecl *MatchedDecl = Result.Nodes.getNodeAs<ValueDecl>("decl");
if( !MatchedDecl || !MatchedDecl->getLocation().isValid() ) {
return;
}
QualType Type = MatchedDecl->getType().getUnqualifiedType();
if( Type.getAsString() == "long" ) {
Check.diag(
MatchedDecl->getLocation(), "Variable %0 declared as long. "
"Prefer int or int64_t.") << MatchedDecl;
} else {
Check.diag(
MatchedDecl->getLocation(), "Variable %0 declared as unsigned long. "
"Prefer unsigned int or uint64_t.") << MatchedDecl;
QualType Type = MatchedDecl->getType();
std::string alternatives = AlternativesFor(Type);
if( alternatives.empty() ) {
return;
}
Check.diag(
MatchedDecl->getLocation(), "Variable %0 declared as %1. %2.") <<
MatchedDecl << Type << alternatives;
}

static void CheckReturn(NoLongCheck &Check, const MatchFinder::MatchResult &Result) {
const FunctionDecl *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("return");
if( !MatchedDecl || !MatchedDecl->getLocation().isValid() ) {
return;
}
QualType Type = MatchedDecl->getReturnType().getUnqualifiedType();
if( Type.getAsString() == "long" ) {
Check.diag(
MatchedDecl->getLocation(), "Function %0 declared as returning long. "
"Prefer int or int64_t.") << MatchedDecl;
} else {
Check.diag(
MatchedDecl->getLocation(), "Function %0 declared as returning unsigned long. "
"Prefer unsigned int or uint64_t.") << MatchedDecl;
QualType Type = MatchedDecl->getReturnType();
std::string alternatives = AlternativesFor(Type);
if( alternatives.empty() ) {
return;
}
Check.diag(
MatchedDecl->getLocation(), "Function %0 declared as returning %1. %2.") <<
MatchedDecl << Type << alternatives;
}

static void CheckCast(NoLongCheck &Check, const MatchFinder::MatchResult &Result) {
const CXXStaticCastExpr *MatchedDecl = Result.Nodes.getNodeAs<CXXStaticCastExpr>("cast");
if( !MatchedDecl ) {
return;
}
QualType Type = MatchedDecl->getType().getUnqualifiedType();
SourceLocation location = MatchedDecl->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
if( Type.getAsString() == "long" ) {
Check.diag(
location, "Static cast to long. Prefer int or int64_t.");
} else {
Check.diag(
location, "Static cast to unsigned long. "
"Prefer unsigned int or uint64_t.");
QualType Type = MatchedDecl->getType();
std::string alternatives = AlternativesFor(Type);
if( alternatives.empty() ) {
return;
}
SourceLocation location = MatchedDecl->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
Check.diag( location, "Static cast to %0. %1.") << Type << alternatives;
}

void NoLongCheck::check(const MatchFinder::MatchResult &Result) {
19 changes: 13 additions & 6 deletions tools/clang-tidy-plugin/test/no-long.cpp
Original file line number Diff line number Diff line change
@@ -2,23 +2,30 @@

#include <stdint.h>

long a;
// CHECK-MESSAGES: warning: Variable 'a' declared as long. Prefer int or int64_t. [cata-no-long]
long a1;
// CHECK-MESSAGES: warning: Variable 'a1' declared as 'long'. Prefer int or int64_t to long. [cata-no-long]

unsigned long b;
// CHECK-MESSAGES: warning: Variable 'b' declared as unsigned long. Prefer unsigned int or uint64_t. [cata-no-long]
unsigned long a2;
// CHECK-MESSAGES: warning: Variable 'a2' declared as 'unsigned long'. Prefer unsigned int or uint64_t to unsigned long. [cata-no-long]

const long a3 = 0;
// CHECK-MESSAGES: warning: Variable 'a3' declared as 'const long'. Prefer int or int64_t to long. [cata-no-long]

long &a4 = a1;
// CHECK-MESSAGES: warning: Variable 'a4' declared as 'long &'. Prefer int or int64_t to long. [cata-no-long]

int64_t c;
uint64_t d;

void f1(long e);
// CHECK-MESSAGES: warning: Variable 'e' declared as long. Prefer int or int64_t. [cata-no-long]
// CHECK-MESSAGES: warning: Variable 'e' declared as 'long'. Prefer int or int64_t to long. [cata-no-long]

long f2();
// CHECK-MESSAGES: warning: Function 'f2' declared as returning long. Prefer int or int64_t. [cata-no-long]
// CHECK-MESSAGES: warning: Function 'f2' declared as returning 'long'. Prefer int or int64_t to long. [cata-no-long]

int64_t f3();
auto f4() -> decltype(0L);

int i1 = static_cast<long>(0);
// CHECK-MESSAGES: warning: Static cast to 'long'. Prefer int or int64_t to long. [cata-no-long]
int i2 = static_cast<int64_t>(0);