[clang-tidy] Avoid incorrect fixes in modernize-use-using
Avoid fixes for typedefs with multiple types and for typedefs with struct definitions. Partially addresses http://llvm.org/PR28334 llvm-svn: 292918
This commit is contained in:
parent
c456e686a9
commit
4b1dfbbc78
|
@ -25,9 +25,10 @@ void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
|
|
||||||
// Checks if 'typedef' keyword can be removed - we do it only if
|
// Checks if 'typedef' keyword can be removed - we do it only if
|
||||||
// it is the only declaration in a declaration chain.
|
// it is the only declaration in a declaration chain.
|
||||||
static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart,
|
static bool CheckRemoval(SourceManager &SM, SourceLocation StartLoc,
|
||||||
const SourceLocation &LocEnd, ASTContext &Context) {
|
ASTContext &Context) {
|
||||||
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(LocStart);
|
assert(StartLoc.isFileID() && "StartLoc must not be in a macro");
|
||||||
|
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StartLoc);
|
||||||
StringRef File = SM.getBufferData(LocInfo.first);
|
StringRef File = SM.getBufferData(LocInfo.first);
|
||||||
const char *TokenBegin = File.data() + LocInfo.second;
|
const char *TokenBegin = File.data() + LocInfo.second;
|
||||||
Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
|
Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
|
||||||
|
@ -35,28 +36,39 @@ static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart,
|
||||||
|
|
||||||
Token Tok;
|
Token Tok;
|
||||||
int ParenLevel = 0;
|
int ParenLevel = 0;
|
||||||
|
bool FoundTypedef = false;
|
||||||
|
|
||||||
while (!DeclLexer.LexFromRawLexer(Tok)) {
|
while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
|
||||||
if (SM.isBeforeInTranslationUnit(LocEnd, Tok.getLocation()))
|
switch (Tok.getKind()) {
|
||||||
break;
|
case tok::l_brace:
|
||||||
if (Tok.getKind() == tok::TokenKind::l_paren)
|
case tok::r_brace:
|
||||||
ParenLevel++;
|
// This might be the `typedef struct {...} T;` case.
|
||||||
if (Tok.getKind() == tok::TokenKind::r_paren)
|
|
||||||
ParenLevel--;
|
|
||||||
if (Tok.getKind() == tok::TokenKind::semi)
|
|
||||||
break;
|
|
||||||
// if there is comma and we are not between open parenthesis then it is
|
|
||||||
// two or more declatarions in this chain
|
|
||||||
if (ParenLevel == 0 && Tok.getKind() == tok::TokenKind::comma)
|
|
||||||
return false;
|
return false;
|
||||||
|
case tok::l_paren:
|
||||||
if (Tok.is(tok::TokenKind::raw_identifier)) {
|
ParenLevel++;
|
||||||
if (Tok.getRawIdentifier() == "typedef")
|
break;
|
||||||
return true;
|
case tok::r_paren:
|
||||||
|
ParenLevel--;
|
||||||
|
break;
|
||||||
|
case tok::comma:
|
||||||
|
if (ParenLevel == 0) {
|
||||||
|
// If there is comma and we are not between open parenthesis then it is
|
||||||
|
// two or more declarations in this chain.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case tok::raw_identifier:
|
||||||
|
if (Tok.getRawIdentifier() == "typedef") {
|
||||||
|
FoundTypedef = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// Sanity check against weird macro cases.
|
||||||
|
return FoundTypedef;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
|
void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
|
@ -67,14 +79,19 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
auto &Context = *Result.Context;
|
auto &Context = *Result.Context;
|
||||||
auto &SM = *Result.SourceManager;
|
auto &SM = *Result.SourceManager;
|
||||||
|
|
||||||
|
if (auto *D = MatchedDecl->getUnderlyingType()->getAsCXXRecordDecl()) {
|
||||||
|
//TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc();
|
||||||
|
llvm::errs() << D->getNameAsString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
auto Diag =
|
auto Diag =
|
||||||
diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'");
|
diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'");
|
||||||
|
|
||||||
if (MatchedDecl->getLocStart().isMacroID())
|
SourceLocation StartLoc = MatchedDecl->getLocStart();
|
||||||
|
if (StartLoc.isMacroID())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (CheckRemoval(SM, MatchedDecl->getLocStart(), MatchedDecl->getLocEnd(),
|
if (CheckRemoval(SM, StartLoc, Context)) {
|
||||||
Context)) {
|
|
||||||
Diag << FixItHint::CreateReplacement(
|
Diag << FixItHint::CreateReplacement(
|
||||||
MatchedDecl->getSourceRange(),
|
MatchedDecl->getSourceRange(),
|
||||||
"using " + MatchedDecl->getNameAsString() + " = " +
|
"using " + MatchedDecl->getNameAsString() + " = " +
|
||||||
|
|
|
@ -78,8 +78,13 @@ typedef Test<my_class *> another;
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
// CHECK-FIXES: using another = Test<my_class *>;
|
// CHECK-FIXES: using another = Test<my_class *>;
|
||||||
|
|
||||||
|
typedef int* PInt;
|
||||||
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
|
// CHECK-FIXES: using PInt = int *;
|
||||||
|
|
||||||
typedef int bla1, bla2, bla3;
|
typedef int bla1, bla2, bla3;
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
|
// CHECK-FIXES: typedef int bla1, bla2, bla3;
|
||||||
|
|
||||||
#define CODE typedef int INT
|
#define CODE typedef int INT
|
||||||
|
|
||||||
|
@ -131,8 +136,15 @@ int typedef Bax;
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
// CHECK-FIXES: using Bax = int;
|
// CHECK-FIXES: using Bax = int;
|
||||||
|
|
||||||
// FIXME: Avoid incorrect fixes in these cases.
|
typedef struct Q1 { int a; } S1;
|
||||||
//typedef struct Q1 { int a; } S1;
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
//typedef struct { int b; } S2;
|
// CHECK-FIXES: typedef struct Q1 { int a; } S1;
|
||||||
//struct Q2 { int c; } typedef S3;
|
typedef struct { int b; } S2;
|
||||||
//struct { int d; } typedef S4;
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
|
// CHECK-FIXES: typedef struct { int b; } S2;
|
||||||
|
struct Q2 { int c; } typedef S3;
|
||||||
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
|
// CHECK-FIXES: struct Q2 { int c; } typedef S3;
|
||||||
|
struct { int d; } typedef S4;
|
||||||
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
|
||||||
|
// CHECK-FIXES: struct { int d; } typedef S4;
|
||||||
|
|
Loading…
Reference in New Issue