clang: lib/Tooling/Transformer/SourceCode.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

22#include "llvm/Support/Errc.h"

23#include "llvm/Support/Error.h"

24#include

25

26using namespace clang;

27

28using llvm::errc;

29using llvm::StringError;

30

35}

36

45 bool Err =

47 Context.getLangOpts(), true);

48 if (Err || !Tok.is(Next))

51}

52

55 bool AllowSystemHeaders) {

56 if (Range.isInvalid())

57 return llvm::make_error(errc::invalid_argument,

58 "Invalid range");

59

60 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())

61 return llvm::make_error(

62 errc::invalid_argument, "Range starts or ends in a macro expansion");

63

64 if (!AllowSystemHeaders) {

65 if (SM.isInSystemHeader(Range.getBegin()) ||

66 SM.isInSystemHeader(Range.getEnd()))

67 return llvm::make_error(errc::invalid_argument,

68 "Range is in system header");

69 }

70

71 std::pair<FileID, unsigned> BeginInfo = SM.getDecomposedLoc(Range.getBegin());

72 std::pair<FileID, unsigned> EndInfo = SM.getDecomposedLoc(Range.getEnd());

73 if (BeginInfo.first != EndInfo.first)

74 return llvm::make_error(

75 errc::invalid_argument, "Range begins and ends in different files");

76

77 if (BeginInfo.second > EndInfo.second)

78 return llvm::make_error(errc::invalid_argument,

79 "Range's begin is past its end");

80

81 return llvm::Error::success();

82}

83

87}

88

92 const auto &Expansion = SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();

93 if (Expansion.isMacroArgExpansion()) {

94

95

96 Loc = Expansion.getSpellingLoc();

97 } else {

98 return true;

99 }

100 }

101 return false;

102}

103

104

105

106

107static std::optional

112 auto &SLoc = SM.getSLocEntry(SM.getFileID(Loc), &Invalid);

114 return std::nullopt;

115 if (auto &Expansion = SLoc.getExpansion();

116 !Expansion.isExpansionTokenRange()) {

117

118

119

120 return Expansion.getExpansionLocRange();

121 }

122 }

123 return std::nullopt;

124}

125

126

127

131 if (Range.isTokenRange()) {

134 if (EndToken) {

136 BeginToken ? BeginToken->getBegin() : Range.getBegin();

137

138

139

141 } else if (BeginToken) {

142

143

144

147 }

148 }

150}

151

155 bool IncludeMacroExpansion) {

157 if (IncludeMacroExpansion) {

159 } else {

163 return {};

164

165 auto B = SM.getSpellingLoc(AdjustedRange.getBegin());

166 auto E = SM.getSpellingLoc(AdjustedRange.getEnd());

167 if (AdjustedRange.isTokenRange())

170 }

172}

173

176 const LangOptions &LangOpts, bool IncludeMacroExpansion) {

178 getRange(EditRange, SM, LangOpts, IncludeMacroExpansion);

180 if (IsInvalid)

181 return std::nullopt;

183}

184

187 const LangOptions &LangOpts, bool IncludeMacroExpansion) {

189 getRange(EditRange, SM, LangOpts, IncludeMacroExpansion);

190 bool IsInvalid =

192 if (IsInvalid)

193 return std::nullopt;

195}

196

199}

200

201static bool contains(const std::settok::TokenKind &Terminators,

202 const Token &Tok) {

203 return Terminators.count(Tok.getKind()) > 0;

204}

205

206

207

208

209

210

211

212

213

216 const std::settok::TokenKind &Terminators,

218 assert(EntityLast.isValid() && "Invalid end location found.");

219

220

221

222

223

224

225 CharSourceRange ExpansionRange = SM.getExpansionRange(EntityLast);

226

227

228 std::unique_ptr Lexer = [&]() {

230 auto FileOffset = SM.getDecomposedLoc(ExpansionRange.getEnd());

231 llvm::StringRef File = SM.getBufferData(FileOffset.first, &Invalid);

232 assert(Invalid && "Cannot get file/offset");

233 return std::make_uniqueclang::Lexer(

234 SM.getLocForStartOfFile(FileOffset.first), LangOpts, File.begin(),

235 File.data() + FileOffset.second, File.end());

236 }();

237

238

240

241

242

243

244

245

246

248 bool Terminated = false;

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270 bool TerminatedByMacro = false;

272 if (Terminators.empty() || contains(Terminators, Tok))

273 Terminated = true;

274 else if (EntityLast.isMacroID()) {

275 Terminated = true;

276 TerminatedByMacro = true;

277 }

278

279

281

282 while (!Terminated) {

283

285

287 case tok::eof:

288

289 case tok::l_brace:

290 case tok::r_brace:

291 case tok::comma:

292 return End;

293

294 case tok::unknown:

296

298 break;

299 default:

300 if (contains(Terminators, Tok))

301 Terminated = true;

303 break;

304 }

305 }

306

307 do {

308

310

312 case tok::unknown:

314

316 break;

317 case tok::comment:

318

320 break;

321 case tok:🚛

322 case tok::comma:

323 if (TerminatedByMacro && contains(Terminators, Tok)) {

325

326 TerminatedByMacro = false;

327 break;

328 }

329

330 return End;

331 default:

332

333 return End;

334 }

335 } while (true);

336}

337

338

339

340

341

342

343

345 if (llvm::isa(D) || llvm::isa(D))

346 return {tok::semi};

347

348 if (llvm::isa(D) || llvm::isa(D))

349 return {tok::r_brace, tok::semi};

350

351 if (llvm::isa(D) || llvm::isa(D))

352 return {tok::comma, tok::semi};

353

354 return {};

355}

356

357

358

359

363 const char *LocChars = SM.getCharacterData(Loc);

364 int i = 0;

366 ++i;

368 ++i;

370}

371

372

373

374

375

378

379

380

381

383 const char *LocChars =

386 "Loc must be a valid character and not the first of the source file.");

388 for (int i = 1; isWhitespace(LocChars[i]); ++i)

390 return true;

391 }

392

393

396 true);

397 if (Failed)

398

399 return true;

400

402 case tok::comment:

403 case tok::l_brace:

404 case tok::r_brace:

405 case tok::eof:

406 return true;

407 default:

408 return false;

409 }

410}

411

417

418

419 if (const auto *Record = llvm::dyn_cast(&Decl)) {

420 if (const auto *T = Record->getDescribedClassTemplate())

421 if (SM.isBeforeInTranslationUnit(T->getBeginLoc(), Range.getBegin()))

422 Range.setBegin(T->getBeginLoc());

423 } else if (const auto *F = llvm::dyn_cast(&Decl)) {

424 if (const auto *T = F->getDescribedFunctionTemplate())

425 if (SM.isBeforeInTranslationUnit(T->getBeginLoc(), Range.getBegin()))

426 Range.setBegin(T->getBeginLoc());

427 }

428

429

430

433 Range.setTokenRange(false);

434

435

436

437

440

441

442

443

444

445

446 if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(),

447 Range.getBegin()) &&

450 LangOpts) &&

452 const StringRef CommentText = Comment->getRawText(SM);

453 if (!CommentText.contains("LINT.IfChange") &&

454 !CommentText.contains("LINT.ThenChange"))

455 Range.setBegin(Comment->getBeginLoc());

456 }

457

461 continue;

463

464

465

467 StringRef Source =

470 continue;

471 llvm::StringRef BeforeAttr =

472 Source.substr(0, SM.getFileOffset(Range.getBegin()));

473 llvm::StringRef BeforeAttrStripped = BeforeAttr.rtrim();

474

475 for (llvm::StringRef Prefix : {"[[", "__attribute__(("}) {

476

477 if (BeforeAttrStripped.ends_with(Prefix)) {

478

479

480

481 Range.setBegin(Range.getBegin().getLocWithOffset(static_cast<int>(

482 -BeforeAttr.size() + BeforeAttrStripped.size() - Prefix.size())));

483 break;

484

485

486

487 }

488 }

489 }

490

491

492

494}

Defines the clang::ASTContext interface.

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

Defines the C++ template declaration subclasses.

llvm::MachO::Record Record

static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)

static bool atOrBeforeSeparation(const SourceManager &SM, SourceLocation Loc, const LangOptions &LangOpts)

static bool startsWithNewline(const SourceManager &SM, const Token &Tok)

static SourceLocation getEntityEndLoc(const SourceManager &SM, SourceLocation EntityLast, const std::set< tok::TokenKind > &Terminators, const LangOptions &LangOpts)

static bool spelledInMacroDefinition(SourceLocation Loc, const SourceManager &SM)

static CharSourceRange getRangeForSplitTokens(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)

static SourceLocation skipWhitespaceAndNewline(const SourceManager &SM, SourceLocation Loc, const LangOptions &LangOpts)

static std::optional< CharSourceRange > getExpansionForSplitToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)

static CharSourceRange getRange(const CharSourceRange &EditRange, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeMacroExpansion)

static std::set< tok::TokenKind > getTerminators(const Decl &D)

Defines the SourceManager interface.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

SourceManager & getSourceManager()

const LangOptions & getLangOpts() const

RawComment * getRawCommentForDeclNoCache(const Decl *D) const

Return the documentation comment attached to a given declaration, without looking into cache.

Attr - This represents one attribute.

SourceLocation getLocation() const

Represents a character-granular source range.

static CharSourceRange getCharRange(SourceRange R)

static CharSourceRange getTokenRange(SourceRange R)

SourceLocation getEnd() const

Decl - This represents one declaration (or definition), e.g.

SourceLocation getEndLoc() const LLVM_READONLY

ASTContext & getASTContext() const LLVM_READONLY

virtual SourceRange getSourceRange() const LLVM_READONLY

Source range that this declaration covers.

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.

static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)

Returns a string for the source that the range encompasses.

void SetKeepWhitespaceMode(bool Val)

SetKeepWhitespaceMode - This method lets clients enable or disable whitespace retention mode.

bool LexFromRawLexer(Token &Result)

LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...

static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)

Given a token range, produce a corresponding CharSourceRange that is not a token range.

static CharSourceRange makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)

Accepts a range and returns a character range with file locations.

static bool getRawToken(SourceLocation Loc, Token &Result, const SourceManager &SM, const LangOptions &LangOpts, bool IgnoreWhiteSpace=false)

Relex the token at the specified location.

static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)

Computes the source location just past the end of the token at this source location.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

SourceLocation getEnd() const

SourceLocation getBegin() const

Token - This structure provides full information about a lexed token.

SourceLocation getEndLoc() const

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

bool is(tok::TokenKind K) const

is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....

tok::TokenKind getKind() const

TokenKind

Provides a simple uniform namespace for tokens from all C languages.

The JSON file list parser is used to communicate input to InstallAPI.

LLVM_READONLY bool isVerticalWhitespace(unsigned char c)

Returns true if this character is vertical ASCII whitespace: '\n', '\r'.

LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)

Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.

LLVM_READONLY bool isWhitespace(unsigned char c)

Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...

const FunctionProtoType * T