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

34 Context.getLangOpts());

35}

36

41 Context.getLangOpts());

45 bool Err =

47 Context.getLangOpts(), true);

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

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

88

89

90

91

94 assert(Loc.isMacroID() && "Location must be in a macro");

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

98 if (Expansion.isMacroArgExpansion()) {

99

100

101 Loc = Expansion.getSpellingLoc();

102 ArgLocs.push_back(Expansion.getExpansionLocStart());

103 } else {

104 return {};

105 }

106 }

107 return ArgLocs;

108}

109

112 if (Range.getBegin().isMacroID() && Range.getEnd().isMacroID()) {

113

114

117 return B.empty() || B != E;

118 }

119

120 return Range.getBegin().isMacroID() || Range.getEnd().isMacroID();

121}

122

123

124

125

126static std::optional

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

133 return std::nullopt;

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

135 !Expansion.isExpansionTokenRange()) {

136

137

138

139 return Expansion.getExpansionLocRange();

140 }

141 }

142 return std::nullopt;

143}

144

145

146

150 if (Range.isTokenRange()) {

153 if (EndToken) {

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

156

157

158

160 } else if (BeginToken) {

161

162

163

165 Range.getEnd());

166 }

167 }

168 return Range;

169}

170

174 bool IncludeMacroExpansion) {

176 if (IncludeMacroExpansion) {

178 } else {

181 return {};

182

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

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

185 if (AdjustedRange.isTokenRange())

188 }

189 return Range;

190}

191

194 const LangOptions &LangOpts, bool IncludeMacroExpansion) {

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

198 if (IsInvalid)

199 return std::nullopt;

201}

202

205 const LangOptions &LangOpts, bool IncludeMacroExpansion) {

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

208 bool IsInvalid =

210 if (IsInvalid)

211 return std::nullopt;

213}

214

218

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

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

222}

223

224

225

226

227

228

229

230

231

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

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

237

238

239

240

241

242

243 CharSourceRange ExpansionRange = SM.getExpansionRange(EntityLast);

244

245

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

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

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

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

251 return std::make_uniqueclang::Lexer(

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

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

254 }();

255

256

258

259

260

261

262

263

264

266 bool Terminated = false;

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288 bool TerminatedByMacro = false;

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

291 Terminated = true;

292 else if (EntityLast.isMacroID()) {

293 Terminated = true;

294 TerminatedByMacro = true;

295 }

296

297

299

300 while (!Terminated) {

301

303

304 switch (Tok.getKind()) {

305 case tok::eof:

306

307 case tok::l_brace:

308 case tok::r_brace:

309 case tok::comma:

310 return End;

311

312 case tok::unknown:

314

315 End = Tok.getEndLoc();

316 break;

317 default:

319 Terminated = true;

320 End = Tok.getEndLoc();

321 break;

322 }

323 }

324

325 do {

326

328

329 switch (Tok.getKind()) {

330 case tok::unknown:

332

333 return Tok.getEndLoc();

334 break;

335 case tok::comment:

336

337 End = Tok.getEndLoc();

338 break;

339 case tok:🚛

340 case tok::comma:

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

342 End = Tok.getEndLoc();

343

344 TerminatedByMacro = false;

345 break;

346 }

347

348 return End;

349 default:

350

351 return End;

352 }

353 } while (true);

354}

355

356

357

358

359

360

361

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

364 return {tok::semi};

365

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

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

368

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

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

371

372 return {};

373}

374

375

376

377

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

382 int i = 0;

384 ++i;

386 ++i;

388}

389

390

391

392

393

396

397

398

399

401 const char *LocChars =

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

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

408 return true;

409 }

410

411

414 true);

415 if (Failed)

416

417 return true;

418

419 switch (Tok.getKind()) {

420 case tok::comment:

421 case tok::l_brace:

422 case tok::r_brace:

423 case tok::eof:

424 return true;

425 default:

426 return false;

427 }

428}

429

433 const LangOptions &LangOpts = Context.getLangOpts();

435

436

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

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

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

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

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

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

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

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

445 }

446

447

448

451 Range.setTokenRange(false);

452

453

454

455

458

459

460

461

462

463

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

465 Range.getBegin()) &&

468 LangOpts) &&

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

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

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

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

474 }

475

479 continue;

481

482

483

485 StringRef Source =

488 continue;

489 llvm::StringRef BeforeAttr =

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

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

492

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

494

495 if (BeforeAttrStripped.ends_with(Prefix)) {

496

497

498

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

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

501 break;

502

503

504

505 }

506 }

507 }

508

509

510

512}

Defines the clang::ASTContext interface.

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

Defines the C++ template declaration subclasses.

FormatToken * Next

The next token in the unwrapped line.

llvm::MachO::Record Record

static llvm::SmallVector< SourceLocation, 2 > getMacroArgumentExpansionLocs(SourceLocation Loc, const SourceManager &SM)

Definition SourceCode.cpp:93

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

Definition SourceCode.cpp:219

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

Definition SourceCode.cpp:394

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

Definition SourceCode.cpp:215

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

Definition SourceCode.cpp:233

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

Definition SourceCode.cpp:147

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

Definition SourceCode.cpp:378

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

Definition SourceCode.cpp:127

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

Definition SourceCode.cpp:171

static bool spelledInMacroDefinition(CharSourceRange Range, const SourceManager &SM)

Definition SourceCode.cpp:110

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

Definition SourceCode.cpp:362

Defines the SourceManager interface.

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

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.

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

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'.

std::pair< FileID, unsigned > FileIDAndOffset

LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)

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

const FunctionProtoType * T

LLVM_READONLY bool isWhitespace(unsigned char c)

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