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