aboutsummaryrefslogtreecommitdiff
path: root/clang-tidy/utils
diff options
context:
space:
mode:
authorJonas Toth <jonas.toth@gmail.com>2018-10-31 16:50:44 +0000
committerJonas Toth <jonas.toth@gmail.com>2018-10-31 16:50:44 +0000
commit5e3a6032b25a92c2da1ca96f09aeaf9ce88d890b (patch)
tree5e7dc412865f737810033e3f7c1939d2553e8b19 /clang-tidy/utils
parent7319efb2073862a1bb46a3325106e28cfd48d0b3 (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.cpp61
-rw-r--r--clang-tidy/utils/LexerUtils.h60
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