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 |
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 = true); |
27 | std::pair<Token, SourceLocation> |
28 | getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM, |
29 | const LangOptions &LangOpts, bool = 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(Loc: L, Result&: T, SM, LangOpts, /*IgnoreWhiteSpace=*/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(Loc: 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(K: tok::eof)) |
87 | return {}; |
88 | Start = PotentialMatch.getLastLoc(); |
89 | } |
90 | } |
91 | |
92 | std::optional<Token> |
93 | (SourceLocation Start, const SourceManager &SM, |
94 | const LangOptions &LangOpts); |
95 | |
96 | // Finds next token that's not a comment. |
97 | std::optional<Token> (SourceLocation Start, |
98 | const SourceManager &SM, |
99 | const LangOptions &LangOpts); |
100 | |
101 | /// Re-lex the provide \p Range and return \c false if either a macro spans |
102 | /// multiple tokens, a pre-processor directive or failure to retrieve the |
103 | /// next token is found, otherwise \c true. |
104 | bool rangeContainsExpansionsOrDirectives(SourceRange Range, |
105 | const SourceManager &SM, |
106 | const LangOptions &LangOpts); |
107 | |
108 | /// Assuming that ``Range`` spans a CVR-qualified type, returns the |
109 | /// token in ``Range`` that is responsible for the qualification. ``Range`` |
110 | /// must be valid with respect to ``SM``. Returns ``std::nullopt`` if no |
111 | /// qualifying tokens are found. |
112 | /// \note: doesn't support member function qualifiers. |
113 | std::optional<Token> getQualifyingToken(tok::TokenKind TK, |
114 | CharSourceRange Range, |
115 | const ASTContext &Context, |
116 | const SourceManager &SM); |
117 | |
118 | /// Stmt->getEndLoc does not always behave the same way depending on Token type. |
119 | /// See implementation for exceptions. |
120 | SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM, |
121 | const LangOptions &LangOpts); |
122 | |
123 | /// For a given FunctionDecl returns the location where you would need to place |
124 | /// the noexcept specifier. |
125 | SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl, |
126 | const SourceManager &SM); |
127 | |
128 | } // namespace tidy::utils::lexer |
129 | } // namespace clang |
130 | |
131 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H |
132 | |