1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
//===--- 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"
#include <optional>
#include <utility>
namespace clang {
class Stmt;
namespace tidy::utils::lexer {
/// Returns previous token or ``tok::unknown`` if not found.
Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
const LangOptions &LangOpts, bool SkipComments = true);
std::pair<Token, SourceLocation>
getPreviousTokenAndStart(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) {
if (Start.isInvalid() || Start.isMacroID())
return {};
while (true) {
SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts);
if (L.isInvalid() || L.isMacroID())
return {};
Token T;
// Returning 'true' is used to signal failure to retrieve the token.
if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true))
return {};
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) {
std::optional<Token> CurrentToken =
Lexer::findNextToken(Start, SM, LangOpts);
if (!CurrentToken)
return {};
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 {};
Start = PotentialMatch.getLastLoc();
}
}
inline std::optional<Token>
findNextTokenIncludingComments(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts) {
return Lexer::findNextToken(Start, SM, LangOpts, true);
}
// Finds next token that's not a comment.
std::optional<Token> 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 ``std::nullopt`` if no
/// qualifying tokens are found.
/// \note: doesn't support member function qualifiers.
std::optional<Token> 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);
/// For a given FunctionDecl returns the location where you would need to place
/// the noexcept specifier.
SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl,
const SourceManager &SM);
} // namespace tidy::utils::lexer
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H
|