1 //===--- LexerUtils.cpp - clang-tidy---------------------------------------===//
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 #include "LexerUtils.h"
10 #include "clang/Basic/SourceManager.h"
11
12 namespace clang {
13 namespace tidy {
14 namespace utils {
15 namespace lexer {
16
getPreviousToken(SourceLocation Location,const SourceManager & SM,const LangOptions & LangOpts,bool SkipComments)17 Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
18 const LangOptions &LangOpts, bool SkipComments) {
19 Token Token;
20 Token.setKind(tok::unknown);
21
22 Location = Location.getLocWithOffset(-1);
23 if (Location.isInvalid())
24 return Token;
25
26 auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location));
27 while (Location != StartOfFile) {
28 Location = Lexer::GetBeginningOfToken(Location, SM, LangOpts);
29 if (!Lexer::getRawToken(Location, Token, SM, LangOpts) &&
30 (!SkipComments || !Token.is(tok::comment))) {
31 break;
32 }
33 Location = Location.getLocWithOffset(-1);
34 }
35 return Token;
36 }
37
findPreviousTokenStart(SourceLocation Start,const SourceManager & SM,const LangOptions & LangOpts)38 SourceLocation findPreviousTokenStart(SourceLocation Start,
39 const SourceManager &SM,
40 const LangOptions &LangOpts) {
41 if (Start.isInvalid() || Start.isMacroID())
42 return SourceLocation();
43
44 SourceLocation BeforeStart = Start.getLocWithOffset(-1);
45 if (BeforeStart.isInvalid() || BeforeStart.isMacroID())
46 return SourceLocation();
47
48 return Lexer::GetBeginningOfToken(BeforeStart, SM, LangOpts);
49 }
50
findPreviousTokenKind(SourceLocation Start,const SourceManager & SM,const LangOptions & LangOpts,tok::TokenKind TK)51 SourceLocation findPreviousTokenKind(SourceLocation Start,
52 const SourceManager &SM,
53 const LangOptions &LangOpts,
54 tok::TokenKind TK) {
55 if (Start.isInvalid() || Start.isMacroID())
56 return SourceLocation();
57
58 while (true) {
59 SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts);
60 if (L.isInvalid() || L.isMacroID())
61 return SourceLocation();
62
63 Token T;
64 if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true))
65 return SourceLocation();
66
67 if (T.is(TK))
68 return T.getLocation();
69
70 Start = L;
71 }
72 }
73
findNextTerminator(SourceLocation Start,const SourceManager & SM,const LangOptions & LangOpts)74 SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
75 const LangOptions &LangOpts) {
76 return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi);
77 }
78
findNextTokenSkippingComments(SourceLocation Start,const SourceManager & SM,const LangOptions & LangOpts)79 Optional<Token> findNextTokenSkippingComments(SourceLocation Start,
80 const SourceManager &SM,
81 const LangOptions &LangOpts) {
82 Optional<Token> CurrentToken;
83 do {
84 CurrentToken = Lexer::findNextToken(Start, SM, LangOpts);
85 } while (CurrentToken && CurrentToken->is(tok::comment));
86 return CurrentToken;
87 }
88
rangeContainsExpansionsOrDirectives(SourceRange Range,const SourceManager & SM,const LangOptions & LangOpts)89 bool rangeContainsExpansionsOrDirectives(SourceRange Range,
90 const SourceManager &SM,
91 const LangOptions &LangOpts) {
92 assert(Range.isValid() && "Invalid Range for relexing provided");
93 SourceLocation Loc = Range.getBegin();
94
95 while (Loc < Range.getEnd()) {
96 if (Loc.isMacroID())
97 return true;
98
99 llvm::Optional<Token> Tok = Lexer::findNextToken(Loc, SM, LangOpts);
100
101 if (!Tok)
102 return true;
103
104 if (Tok->is(tok::hash))
105 return true;
106
107 Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts).getLocWithOffset(1);
108 }
109
110 return false;
111 }
112
getQualifyingToken(tok::TokenKind TK,CharSourceRange Range,const ASTContext & Context,const SourceManager & SM)113 llvm::Optional<Token> getQualifyingToken(tok::TokenKind TK,
114 CharSourceRange Range,
115 const ASTContext &Context,
116 const SourceManager &SM) {
117 assert((TK == tok::kw_const || TK == tok::kw_volatile ||
118 TK == tok::kw_restrict) &&
119 "TK is not a qualifier keyword");
120 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin());
121 StringRef File = SM.getBufferData(LocInfo.first);
122 Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
123 File.begin(), File.data() + LocInfo.second, File.end());
124 llvm::Optional<Token> LastMatchBeforeTemplate;
125 llvm::Optional<Token> LastMatchAfterTemplate;
126 bool SawTemplate = false;
127 Token Tok;
128 while (!RawLexer.LexFromRawLexer(Tok) &&
129 Range.getEnd() != Tok.getLocation() &&
130 !SM.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) {
131 if (Tok.is(tok::raw_identifier)) {
132 IdentifierInfo &Info = Context.Idents.get(
133 StringRef(SM.getCharacterData(Tok.getLocation()), Tok.getLength()));
134 Tok.setIdentifierInfo(&Info);
135 Tok.setKind(Info.getTokenID());
136 }
137 if (Tok.is(tok::less))
138 SawTemplate = true;
139 else if (Tok.isOneOf(tok::greater, tok::greatergreater))
140 LastMatchAfterTemplate = None;
141 else if (Tok.is(TK)) {
142 if (SawTemplate)
143 LastMatchAfterTemplate = Tok;
144 else
145 LastMatchBeforeTemplate = Tok;
146 }
147 }
148 return LastMatchAfterTemplate != None ? LastMatchAfterTemplate
149 : LastMatchBeforeTemplate;
150 }
151 } // namespace lexer
152 } // namespace utils
153 } // namespace tidy
154 } // namespace clang
155