//===--- LexerUtils.h - clang-tidy-------------------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H #include "clang/AST/ASTContext.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/Lexer.h" namespace clang { class Stmt; namespace tidy { namespace utils { namespace lexer { /// Returns previous token or ``tok::unknown`` if not found. 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 SourceLocation findPreviousAnyTokenKind(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts, TokenKind TK, TokenKinds... TKs) { if (Start.isInvalid() || Start.isMacroID()) return SourceLocation(); 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, /*IgnoreWhiteSpace=*/true)) return SourceLocation(); if (T.isOneOf(TK, TKs...)) return T.getLocation(); Start = L; } } template SourceLocation findNextAnyTokenKind(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts, TokenKind TK, TokenKinds... TKs) { while (true) { Optional CurrentToken = Lexer::findNextToken(Start, SM, LangOpts); if (!CurrentToken) return SourceLocation(); Token PotentialMatch = *CurrentToken; if (PotentialMatch.isOneOf(TK, TKs...)) return PotentialMatch.getLocation(); // If we reach the end of the file, and eof is not the target token, we stop // the loop, otherwise we will get infinite loop (findNextToken will return // eof on eof). if (PotentialMatch.is(tok::eof)) return SourceLocation(); Start = PotentialMatch.getLastLoc(); } } // Finds next token that's not a comment. Optional findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts); /// 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); /// Assuming that ``Range`` spans a CVR-qualified type, returns the /// token in ``Range`` that is responsible for the qualification. ``Range`` /// must be valid with respect to ``SM``. Returns ``None`` if no qualifying /// tokens are found. /// \note: doesn't support member function qualifiers. llvm::Optional getQualifyingToken(tok::TokenKind TK, CharSourceRange Range, const ASTContext &Context, const SourceManager &SM); /// Stmt->getEndLoc does not always behave the same way depending on Token type. /// See implementation for exceptions. SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM, const LangOptions &LangOpts); } // namespace lexer } // namespace utils } // namespace tidy } // namespace clang #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H