diff options
author | Jonas Toth <jonas.toth@gmail.com> | 2018-10-31 16:50:44 +0000 |
---|---|---|
committer | Jonas Toth <jonas.toth@gmail.com> | 2018-10-31 16:50:44 +0000 |
commit | 5e3a6032b25a92c2da1ca96f09aeaf9ce88d890b (patch) | |
tree | 5e7dc412865f737810033e3f7c1939d2553e8b19 /clang-tidy/utils | |
parent | 7319efb2073862a1bb46a3325106e28cfd48d0b3 (diff) |
[clang-tidy] new check 'readability-isolate-declaration'
Summary:
This patch introduces a new clang-tidy check that matches on all `declStmt` that declare more then one variable
and transform them into one statement per declaration if possible.
It currently only focusses on variable declarations but should be extended to cover more kinds of declarations in the future.
It is related to https://reviews.llvm.org/D27621 and does use it's extensive test-suite. Thank you to firolino for his work!
Reviewers: rsmith, aaron.ballman, alexfh, hokein, kbobyrev
Reviewed By: aaron.ballman
Subscribers: ZaMaZaN4iK, mgehre, nemanjai, kbarton, lebedev.ri, Eugene.Zelenko, mgorny, xazax.hun, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D51949
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@345735 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy/utils')
-rw-r--r-- | clang-tidy/utils/LexerUtils.cpp | 61 | ||||
-rw-r--r-- | clang-tidy/utils/LexerUtils.h | 60 |
2 files changed, 121 insertions, 0 deletions
diff --git a/clang-tidy/utils/LexerUtils.cpp b/clang-tidy/utils/LexerUtils.cpp index 1b52347e..82097978 100644 --- a/clang-tidy/utils/LexerUtils.cpp +++ b/clang-tidy/utils/LexerUtils.cpp @@ -31,6 +31,67 @@ Token getPreviousToken(SourceLocation Location, const SourceManager &SM, return Token; } +SourceLocation findPreviousTokenStart(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts) { + if (Start.isInvalid() || Start.isMacroID()) + return SourceLocation(); + + SourceLocation BeforeStart = Start.getLocWithOffset(-1); + if (BeforeStart.isInvalid() || BeforeStart.isMacroID()) + return SourceLocation(); + + return Lexer::GetBeginningOfToken(BeforeStart, SM, LangOpts); +} + +SourceLocation findPreviousTokenKind(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts, + tok::TokenKind TK) { + while (true) { + SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); + if (L.isInvalid() || L.isMacroID()) + return SourceLocation(); + + Token T; + if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true)) + return SourceLocation(); + + if (T.is(TK)) + return T.getLocation(); + + Start = L; + } +} + +SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, + const LangOptions &LangOpts) { + return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi); +} + +bool rangeContainsExpansionsOrDirectives(SourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + assert(Range.isValid() && "Invalid Range for relexing provided"); + SourceLocation Loc = Range.getBegin(); + + while (Loc < Range.getEnd()) { + if (Loc.isMacroID()) + return true; + + llvm::Optional<Token> Tok = Lexer::findNextToken(Loc, SM, LangOpts); + + if (!Tok) + return true; + + if (Tok->is(tok::hash)) + return true; + + Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts).getLocWithOffset(1); + } + + return false; +} } // namespace lexer } // namespace utils } // namespace tidy diff --git a/clang-tidy/utils/LexerUtils.h b/clang-tidy/utils/LexerUtils.h index 0eb5e56e..f81fdae4 100644 --- a/clang-tidy/utils/LexerUtils.h +++ b/clang-tidy/utils/LexerUtils.h @@ -22,6 +22,66 @@ namespace lexer { Token getPreviousToken(SourceLocation Location, const SourceManager &SM, const LangOptions &LangOpts, bool SkipComments = true); +SourceLocation findPreviousTokenStart(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts); + +SourceLocation findPreviousTokenKind(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts, + tok::TokenKind TK); + +SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, + const LangOptions &LangOpts); + +template <typename TokenKind, typename... TokenKinds> +SourceLocation findPreviousAnyTokenKind(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts, + TokenKind TK, TokenKinds... TKs) { + while (true) { + SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); + if (L.isInvalid() || L.isMacroID()) + return SourceLocation(); + + Token T; + // Returning 'true' is used to signal failure to retrieve the token. + if (Lexer::getRawToken(L, T, SM, LangOpts)) + return SourceLocation(); + + if (T.isOneOf(TK, TKs...)) + return T.getLocation(); + + Start = L; + } +} + +template <typename TokenKind, typename... TokenKinds> +SourceLocation findNextAnyTokenKind(SourceLocation Start, + const SourceManager &SM, + const LangOptions &LangOpts, TokenKind TK, + TokenKinds... TKs) { + while (true) { + Optional<Token> CurrentToken = Lexer::findNextToken(Start, SM, LangOpts); + + if (!CurrentToken) + return SourceLocation(); + + Token PotentialMatch = *CurrentToken; + if (PotentialMatch.isOneOf(TK, TKs...)) + return PotentialMatch.getLocation(); + + Start = PotentialMatch.getLastLoc(); + } +} + +/// Re-lex the provide \p Range and return \c false if either a macro spans +/// multiple tokens, a pre-processor directive or failure to retrieve the +/// next token is found, otherwise \c true. +bool rangeContainsExpansionsOrDirectives(SourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts); + } // namespace lexer } // namespace utils } // namespace tidy |