1 //===--- LexerUtils.h - clang-tidy-------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H 11 12 #include "clang/AST/ASTContext.h" 13 #include "clang/Basic/TokenKinds.h" 14 #include "clang/Lex/Lexer.h" 15 #include <optional> 16 #include <utility> 17 18 namespace clang { 19 20 class Stmt; 21 22 namespace tidy::utils::lexer { 23 24 /// Returns previous token or ``tok::unknown`` if not found. 25 Token getPreviousToken(SourceLocation Location, const SourceManager &SM, 26 const LangOptions &LangOpts, bool SkipComments = true); 27 std::pair<Token, SourceLocation> 28 getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM, 29 const LangOptions &LangOpts, bool SkipComments = true); 30 31 SourceLocation findPreviousTokenStart(SourceLocation Start, 32 const SourceManager &SM, 33 const LangOptions &LangOpts); 34 35 SourceLocation findPreviousTokenKind(SourceLocation Start, 36 const SourceManager &SM, 37 const LangOptions &LangOpts, 38 tok::TokenKind TK); 39 40 SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, 41 const LangOptions &LangOpts); 42 43 template <typename TokenKind, typename... TokenKinds> 44 SourceLocation findPreviousAnyTokenKind(SourceLocation Start, 45 const SourceManager &SM, 46 const LangOptions &LangOpts, 47 TokenKind TK, TokenKinds... TKs) { 48 if (Start.isInvalid() || Start.isMacroID()) 49 return {}; 50 while (true) { 51 SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); 52 if (L.isInvalid() || L.isMacroID()) 53 return {}; 54 55 Token T; 56 // Returning 'true' is used to signal failure to retrieve the token. 57 if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true)) 58 return {}; 59 60 if (T.isOneOf(TK, TKs...)) 61 return T.getLocation(); 62 63 Start = L; 64 } 65 } 66 67 template <typename TokenKind, typename... TokenKinds> 68 SourceLocation findNextAnyTokenKind(SourceLocation Start, 69 const SourceManager &SM, 70 const LangOptions &LangOpts, TokenKind TK, 71 TokenKinds... TKs) { 72 while (true) { 73 std::optional<Token> CurrentToken = 74 Lexer::findNextToken(Start, SM, LangOpts); 75 76 if (!CurrentToken) 77 return {}; 78 79 Token PotentialMatch = *CurrentToken; 80 if (PotentialMatch.isOneOf(TK, TKs...)) 81 return PotentialMatch.getLocation(); 82 83 // If we reach the end of the file, and eof is not the target token, we stop 84 // the loop, otherwise we will get infinite loop (findNextToken will return 85 // eof on eof). 86 if (PotentialMatch.is(tok::eof)) 87 return {}; 88 Start = PotentialMatch.getLastLoc(); 89 } 90 } 91 92 inline std::optional<Token> 93 findNextTokenIncludingComments(SourceLocation Start, const SourceManager &SM, 94 const LangOptions &LangOpts) { 95 return Lexer::findNextToken(Start, SM, LangOpts, true); 96 } 97 98 // Finds next token that's not a comment. 99 std::optional<Token> findNextTokenSkippingComments(SourceLocation Start, 100 const SourceManager &SM, 101 const LangOptions &LangOpts); 102 103 /// Re-lex the provide \p Range and return \c false if either a macro spans 104 /// multiple tokens, a pre-processor directive or failure to retrieve the 105 /// next token is found, otherwise \c true. 106 bool rangeContainsExpansionsOrDirectives(SourceRange Range, 107 const SourceManager &SM, 108 const LangOptions &LangOpts); 109 110 /// Assuming that ``Range`` spans a CVR-qualified type, returns the 111 /// token in ``Range`` that is responsible for the qualification. ``Range`` 112 /// must be valid with respect to ``SM``. Returns ``std::nullopt`` if no 113 /// qualifying tokens are found. 114 /// \note: doesn't support member function qualifiers. 115 std::optional<Token> getQualifyingToken(tok::TokenKind TK, 116 CharSourceRange Range, 117 const ASTContext &Context, 118 const SourceManager &SM); 119 120 /// Stmt->getEndLoc does not always behave the same way depending on Token type. 121 /// See implementation for exceptions. 122 SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM, 123 const LangOptions &LangOpts); 124 125 /// For a given FunctionDecl returns the location where you would need to place 126 /// the noexcept specifier. 127 SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl, 128 const SourceManager &SM); 129 130 } // namespace tidy::utils::lexer 131 } // namespace clang 132 133 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H 134