2015-12-30 18:24:40 +08:00
|
|
|
//===--- LexerUtils.cpp - clang-tidy---------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-12-30 18:24:40 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "LexerUtils.h"
|
2021-03-25 21:44:41 +08:00
|
|
|
#include "clang/AST/AST.h"
|
2020-02-28 03:01:58 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2015-12-30 18:24:40 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace tidy {
|
2016-05-03 10:54:05 +08:00
|
|
|
namespace utils {
|
|
|
|
namespace lexer {
|
2015-12-30 18:24:40 +08:00
|
|
|
|
2018-10-05 22:15:19 +08:00
|
|
|
Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts, bool SkipComments) {
|
2015-12-30 18:24:40 +08:00
|
|
|
Token Token;
|
|
|
|
Token.setKind(tok::unknown);
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
|
2015-12-30 18:24:40 +08:00
|
|
|
Location = Location.getLocWithOffset(-1);
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
if (Location.isInvalid())
|
|
|
|
return Token;
|
|
|
|
|
2018-10-05 22:15:19 +08:00
|
|
|
auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location));
|
2015-12-30 18:24:40 +08:00
|
|
|
while (Location != StartOfFile) {
|
2018-10-05 22:15:19 +08:00
|
|
|
Location = Lexer::GetBeginningOfToken(Location, SM, LangOpts);
|
|
|
|
if (!Lexer::getRawToken(Location, Token, SM, LangOpts) &&
|
2017-02-06 23:46:33 +08:00
|
|
|
(!SkipComments || !Token.is(tok::comment))) {
|
2015-12-30 18:24:40 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Location = Location.getLocWithOffset(-1);
|
|
|
|
}
|
|
|
|
return Token;
|
|
|
|
}
|
|
|
|
|
[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
llvm-svn: 345735
2018-11-01 00:50:44 +08:00
|
|
|
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) {
|
[clang-tidy] implement utility-function to add 'const' to variables
Summary:
This patch extends the already existing facility to add 'const' to variables
to be more flexible and correct. The previous version did not consider pointers
as value AND pointee. For future automatic introduction for const-correctness
this shortcoming needs to be fixed.
It always allows configuration where the 'const' token is inserted, either on
the left side (if possible) or the right side.
It adds many unit-tests to the utility-function that did not exist before, as
the function was implicitly tested through clang-tidy checks. These
tests were not changed, as the API is still compatible.
Reviewers: aaron.ballman, hokein, alexfh, shuaiwang, lebedev.ri
Reviewed By: aaron.ballman
Subscribers: jdoerfert, mgorny, xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54395
2020-01-04 03:36:49 +08:00
|
|
|
if (Start.isInvalid() || Start.isMacroID())
|
|
|
|
return SourceLocation();
|
|
|
|
|
[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
llvm-svn: 345735
2018-11-01 00:50:44 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-21 04:36:45 +08:00
|
|
|
Optional<Token> findNextTokenSkippingComments(SourceLocation Start,
|
|
|
|
const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts) {
|
|
|
|
Optional<Token> CurrentToken;
|
|
|
|
do {
|
|
|
|
CurrentToken = Lexer::findNextToken(Start, SM, LangOpts);
|
|
|
|
} while (CurrentToken && CurrentToken->is(tok::comment));
|
|
|
|
return CurrentToken;
|
|
|
|
}
|
|
|
|
|
[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
llvm-svn: 345735
2018-11-01 00:50:44 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-11-01 03:11:38 +08:00
|
|
|
|
2019-12-24 23:10:01 +08:00
|
|
|
llvm::Optional<Token> getQualifyingToken(tok::TokenKind TK,
|
|
|
|
CharSourceRange Range,
|
|
|
|
const ASTContext &Context,
|
|
|
|
const SourceManager &SM) {
|
|
|
|
assert((TK == tok::kw_const || TK == tok::kw_volatile ||
|
|
|
|
TK == tok::kw_restrict) &&
|
|
|
|
"TK is not a qualifier keyword");
|
2018-11-01 03:11:38 +08:00
|
|
|
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin());
|
|
|
|
StringRef File = SM.getBufferData(LocInfo.first);
|
|
|
|
Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
|
|
|
|
File.begin(), File.data() + LocInfo.second, File.end());
|
2019-12-24 23:10:01 +08:00
|
|
|
llvm::Optional<Token> LastMatchBeforeTemplate;
|
|
|
|
llvm::Optional<Token> LastMatchAfterTemplate;
|
|
|
|
bool SawTemplate = false;
|
2018-11-01 03:11:38 +08:00
|
|
|
Token Tok;
|
|
|
|
while (!RawLexer.LexFromRawLexer(Tok) &&
|
|
|
|
Range.getEnd() != Tok.getLocation() &&
|
|
|
|
!SM.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) {
|
|
|
|
if (Tok.is(tok::raw_identifier)) {
|
|
|
|
IdentifierInfo &Info = Context.Idents.get(
|
|
|
|
StringRef(SM.getCharacterData(Tok.getLocation()), Tok.getLength()));
|
|
|
|
Tok.setIdentifierInfo(&Info);
|
|
|
|
Tok.setKind(Info.getTokenID());
|
|
|
|
}
|
2019-12-24 23:10:01 +08:00
|
|
|
if (Tok.is(tok::less))
|
|
|
|
SawTemplate = true;
|
|
|
|
else if (Tok.isOneOf(tok::greater, tok::greatergreater))
|
|
|
|
LastMatchAfterTemplate = None;
|
|
|
|
else if (Tok.is(TK)) {
|
|
|
|
if (SawTemplate)
|
|
|
|
LastMatchAfterTemplate = Tok;
|
|
|
|
else
|
|
|
|
LastMatchBeforeTemplate = Tok;
|
|
|
|
}
|
2018-11-01 03:11:38 +08:00
|
|
|
}
|
2019-12-24 23:10:01 +08:00
|
|
|
return LastMatchAfterTemplate != None ? LastMatchAfterTemplate
|
|
|
|
: LastMatchBeforeTemplate;
|
2018-11-01 03:11:38 +08:00
|
|
|
}
|
2021-03-25 21:44:41 +08:00
|
|
|
|
|
|
|
static bool breakAndReturnEnd(const Stmt &S) {
|
|
|
|
return isa<CompoundStmt, DeclStmt, NullStmt>(S);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool breakAndReturnEndPlus1Token(const Stmt &S) {
|
|
|
|
return isa<Expr, DoStmt, ReturnStmt, BreakStmt, ContinueStmt, GotoStmt, SEHLeaveStmt>(S);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given a Stmt which does not include it's semicolon this method returns the
|
|
|
|
// SourceLocation of the semicolon.
|
|
|
|
static SourceLocation getSemicolonAfterStmtEndLoc(const SourceLocation &EndLoc,
|
|
|
|
const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts) {
|
|
|
|
|
|
|
|
if (EndLoc.isMacroID()) {
|
|
|
|
// Assuming EndLoc points to a function call foo within macro F.
|
|
|
|
// This method is supposed to return location of the semicolon within
|
|
|
|
// those macro arguments:
|
|
|
|
// F ( foo() ; )
|
|
|
|
// ^ EndLoc ^ SpellingLoc ^ next token of SpellingLoc
|
|
|
|
const SourceLocation SpellingLoc = SM.getSpellingLoc(EndLoc);
|
|
|
|
Optional<Token> NextTok =
|
|
|
|
findNextTokenSkippingComments(SpellingLoc, SM, LangOpts);
|
|
|
|
|
|
|
|
// Was the next token found successfully?
|
|
|
|
// All macro issues are simply resolved by ensuring it's a semicolon.
|
|
|
|
if (NextTok && NextTok->is(tok::TokenKind::semi)) {
|
|
|
|
// Ideally this would return `F` with spelling location `;` (NextTok)
|
|
|
|
// following the examle above. For now simply return NextTok location.
|
|
|
|
return NextTok->getLocation();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fallthrough to 'normal handling'.
|
|
|
|
// F ( foo() ) ;
|
|
|
|
// ^ EndLoc ^ SpellingLoc ) ^ next token of EndLoc
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<Token> NextTok = findNextTokenSkippingComments(EndLoc, SM, LangOpts);
|
|
|
|
|
|
|
|
// Testing for semicolon again avoids some issues with macros.
|
|
|
|
if (NextTok && NextTok->is(tok::TokenKind::semi))
|
|
|
|
return NextTok->getLocation();
|
|
|
|
|
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts) {
|
|
|
|
|
|
|
|
const Stmt *LastChild = &S;
|
|
|
|
while (!LastChild->children().empty() && !breakAndReturnEnd(*LastChild) &&
|
|
|
|
!breakAndReturnEndPlus1Token(*LastChild)) {
|
|
|
|
for (const Stmt *Child : LastChild->children())
|
|
|
|
LastChild = Child;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!breakAndReturnEnd(*LastChild) &&
|
|
|
|
breakAndReturnEndPlus1Token(*LastChild))
|
|
|
|
return getSemicolonAfterStmtEndLoc(S.getEndLoc(), SM, LangOpts);
|
|
|
|
|
|
|
|
return S.getEndLoc();
|
|
|
|
}
|
|
|
|
|
2016-05-03 10:54:05 +08:00
|
|
|
} // namespace lexer
|
|
|
|
} // namespace utils
|
2015-12-30 18:24:40 +08:00
|
|
|
} // namespace tidy
|
|
|
|
} // namespace clang
|