clang: lib/Rewrite/Rewriter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

20#include "llvm/ADT/RewriteBuffer.h"

21#include "llvm/ADT/RewriteRope.h"

22#include "llvm/ADT/SmallVector.h"

23#include "llvm/ADT/StringRef.h"

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

25#include "llvm/Support/raw_ostream.h"

26#include

27#include

28#include

29#include

30

31using namespace clang;

32using llvm::RewriteBuffer;

33

34

35

36

37

38

39

41 return c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r';

42}

43

44

45

50

51 FileID StartFileID, EndFileID;

52 unsigned StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);

53 unsigned EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);

54

55 if (StartFileID != EndFileID)

56 return -1;

57

58

59

60 std::map<FileID, RewriteBuffer>::const_iterator I =

61 RewriteBuffers.find(StartFileID);

62 if (I != RewriteBuffers.end()) {

63 const RewriteBuffer &RB = I->second;

66 }

67

68

69

70 if (Range.isTokenRange())

72

73 return EndOff-StartOff;

74}

75

78}

79

80

81

82

83

84

88 return {};

89

90 FileID StartFileID, EndFileID;

91 unsigned StartOff, EndOff;

92 StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);

93 EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);

94

95 if (StartFileID != EndFileID)

96 return {};

97

98

99

100 std::map<FileID, RewriteBuffer>::const_iterator I =

101 RewriteBuffers.find(StartFileID);

102 if (I == RewriteBuffers.end()) {

103

105

106

107

108 if (Range.isTokenRange())

109 EndOff +=

111 return std::string(Ptr, Ptr+EndOff-StartOff);

112 }

113

114 const RewriteBuffer &RB = I->second;

115 EndOff = RB.getMappedOffset(EndOff, true);

116 StartOff = RB.getMappedOffset(StartOff);

117

118

119

120 if (Range.isTokenRange())

122

123

124 RewriteBuffer::iterator Start = RB.begin();

125 std::advance(Start, StartOff);

126 RewriteBuffer::iterator End = Start;

127 assert(EndOff >= StartOff && "Invalid iteration distance");

128 std::advance(End, EndOff-StartOff);

129

130 return std::string(Start, End);

131}

132

135 assert(Loc.isValid() && "Invalid location");

137 FID = V.first;

138 return V.second;

139}

140

141

143 std::map<FileID, RewriteBuffer>::iterator I =

144 RewriteBuffers.lower_bound(FID);

145 if (I != RewriteBuffers.end() && I->first == FID)

146 return I->second;

147 I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));

148

150 I->second.Initialize(MB.begin(), MB.end());

151

152 return I->second;

153}

154

155

156

158 bool InsertAfter, bool indentNewLines) {

161 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);

162

164 if (indentNewLines && Str.contains('\n')) {

166

167 unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;

171

172

173 StringRef indentSpace;

174 {

175 unsigned i = lineOffs;

177 ++i;

178 indentSpace = MB.substr(lineOffs, i-lineOffs);

179 }

180

182 Str.split(lines, "\n");

183

184 for (unsigned i = 0, e = lines.size(); i != e; ++i) {

185 indentedStr += lines[i];

186 if (i < e-1) {

187 indentedStr += '\n';

188 indentedStr += indentSpace;

189 }

190 }

191 Str = indentedStr.str();

192 }

193

194 getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);

195 return false;

196}

197

201 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);

205 getEditBuffer(FID).InsertText(StartOffs, Str, true);

206 return false;

207}

208

209

214 unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);

216 return false;

217}

218

219

220

221

223 StringRef NewStr) {

226 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);

227

228 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);

229 return false;

230}

231

233 if (isRewritable(range.getBegin())) return true;

234 if (isRewritable(range.getEnd())) return true;

235 if (replacementRange.isInvalid()) return true;

238 unsigned newLength = getRangeSize(replacementRange);

240 unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),

241 FID);

243 return ReplaceText(start, origLength, MB.substr(newOffs, newLength));

244}

245

248 if (range.isInvalid()) return true;

249 if (isRewritable(range.getBegin())) return true;

250 if (isRewritable(range.getEnd())) return true;

251 if (isRewritable(parentIndent)) return true;

252

253 FileID StartFileID, EndFileID, parentFileID;

254 unsigned StartOff, EndOff, parentOff;

255

256 StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID);

257 EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID);

258 parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);

259

260 if (StartFileID != EndFileID || StartFileID != parentFileID)

261 return true;

262 if (StartOff > EndOff)

263 return true;

264

265 FileID FID = StartFileID;

267

268 unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;

269 unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;

270 unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;

271

274

275

276 unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];

277 unsigned startLineOffs = Content->SourceLineCache[startLineNo];

278

279

280 StringRef parentSpace, startSpace;

281 {

282 unsigned i = parentLineOffs;

284 ++i;

285 parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);

286

287 i = startLineOffs;

289 ++i;

290 startSpace = MB.substr(startLineOffs, i-startLineOffs);

291 }

292 if (parentSpace.size() >= startSpace.size())

293 return true;

294 if (!startSpace.starts_with(parentSpace))

295 return true;

296

297 StringRef indent = startSpace.substr(parentSpace.size());

298

299

301 for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {

303 unsigned i = offs;

305 ++i;

306 StringRef origIndent = MB.substr(offs, i-offs);

307 if (origIndent.starts_with(startSpace))

308 RB.InsertText(offs, indent, false);

309 }

310

311 return false;

312}

313

315 bool AllWritten = true;

317 unsigned OverwriteFailure = Diag.getCustomDiagID(

323 if (auto Error = llvm::writeToOutput(Path, [&](llvm::raw_ostream &OS) {

324 I->second.write(OS);

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

326 })) {

327 Diag.Report(OverwriteFailure)

328 << Entry->getName() << llvm::toString(std::move(Error));

329 AllWritten = false;

330 }

331 }

332 return !AllWritten;

333}

Defines the Diagnostic-related interfaces.

Defines the Diagnostic IDs-related interfaces.

static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)

Produce a diagnostic highlighting some portion of a literal.

static bool isWhitespaceExceptNL(unsigned char c)

Return true if this character is non-new-line whitespace: ' ', '\t', '\f', '\v', '\r'.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

__device__ __2f16 float c

Represents a character-granular source range.

static CharSourceRange getTokenRange(SourceRange R)

StringRef getName() const

The name of this FileEntry.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

bool makeAbsolutePath(SmallVectorImpl< char > &Path) const

Makes Path absolute taking into account FileSystemOptions and the working directory option.

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

MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...

std::map< FileID, llvm::RewriteBuffer >::iterator buffer_iterator

int getRangeSize(SourceRange Range, RewriteOptions opts=RewriteOptions()) const

getRangeSize - Return the size in bytes of the specified range if they are in the same file.

bool InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter=true, bool indentNewLines=false)

InsertText - Insert the specified string at the specified location in the original buffer.

bool RemoveText(SourceLocation Start, unsigned Length, RewriteOptions opts=RewriteOptions())

RemoveText - Remove the specified text region.

static bool isRewritable(SourceLocation Loc)

isRewritable - Return true if this location is a raw file location, which is rewritable.

buffer_iterator buffer_end()

SourceManager & getSourceMgr() const

buffer_iterator buffer_begin()

std::string getRewrittenText(CharSourceRange Range) const

getRewrittenText - Return the rewritten form of the text in the specified range.

bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent)

Increase indentation for the lines between the given source range.

bool InsertTextAfterToken(SourceLocation Loc, StringRef Str)

Insert the specified string after the token in the specified location.

llvm::RewriteBuffer & getEditBuffer(FileID FID)

getEditBuffer - This is like getRewriteBufferFor, but always returns a buffer, and allows you to writ...

bool overwriteChangedFiles()

overwriteChangedFiles - Save all changed files to disk.

bool ReplaceText(SourceLocation Start, unsigned OrigLength, StringRef NewStr)

ReplaceText - This method replaces a range of characters in the input buffer with a new string.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

DiagnosticsEngine & getDiagnostics() const

OptionalFileEntryRef getFileEntryRefForID(FileID FID) const

Returns the FileEntryRef for the provided FileID.

StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const

Return a StringRef to the source buffer data for the specified FileID.

FileManager & getFileManager() const

const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const

Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.

unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const

Given a SourceLocation, return the spelling line number for the position indicated.

std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const

Decompose the specified location into a raw FileID + Offset pair.

const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

One instance of this struct is kept for every file loaded or used.

LineOffsetMapping SourceLineCache

A bump pointer allocated array of offsets for each source line.

const ContentCache & getContentCache() const

const FileInfo & getFile() const

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

bool IncludeInsertsAtBeginOfRange

Given a source range, true to include previous inserts at the beginning of the range as part of the r...

bool IncludeInsertsAtEndOfRange

Given a source range, true to include previous inserts at the end of the range as part of the range i...

bool RemoveLineIfEmpty

If true and removing some text leaves a blank line also remove the empty line (false by default).