clang: lib/Tooling/Refactoring/AtomicChange.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

11#include "llvm/Support/YAMLTraits.h"

12#include

13

15

16namespace {

17

18

19

20

21struct NormalizedAtomicChange {

22 NormalizedAtomicChange() = default;

23

24 NormalizedAtomicChange(const llvm::yaml::IO &) {}

25

26

27

28 NormalizedAtomicChange(const llvm::yaml::IO &,

30 : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),

31 InsertedHeaders(E.getInsertedHeaders()),

32 RemovedHeaders(E.getRemovedHeaders()),

33 Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}

34

35

37 llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. "

38 "Use AtomicChange::convertFromYAML instead.");

39 }

40 std::string Key;

41 std::string FilePath;

42 std::string Error;

43 std::vectorstd::string InsertedHeaders;

44 std::vectorstd::string RemovedHeaders;

45 std::vectorclang::tooling::Replacement Replaces;

46};

47}

48

49namespace llvm {

50namespace yaml {

51

52

53

54template <> struct MappingTraits {

55 static void mapping(IO &Io, NormalizedAtomicChange &Doc) {

56 Io.mapRequired("Key", Doc.Key);

57 Io.mapRequired("FilePath", Doc.FilePath);

58 Io.mapRequired("Error", Doc.Error);

59 Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders);

60 Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders);

61 Io.mapRequired("Replacements", Doc.Replaces);

62 }

63};

64

65

66

67template <> struct MappingTraits<clang::tooling::AtomicChange> {

69 MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>

70 Keys(Io, Doc);

71 Io.mapRequired("Key", Keys->Key);

72 Io.mapRequired("FilePath", Keys->FilePath);

73 Io.mapRequired("Error", Keys->Error);

74 Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders);

75 Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders);

76 Io.mapRequired("Replacements", Keys->Replaces);

77 }

78};

79

80}

81}

82

84namespace tooling {

85namespace {

86

87

88

89bool violatesColumnLimit(llvm::StringRef Code, unsigned ColumnLimit,

90 unsigned Start, unsigned End) {

91 auto StartPos = Code.rfind('\n', Start);

92 StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1;

93

94 auto EndPos = Code.find("\n", End);

95 if (EndPos == llvm::StringRef::npos)

96 EndPos = Code.size();

97

99 Code.substr(StartPos, EndPos - StartPos).split(Lines, '\n');

100 for (llvm::StringRef Line : Lines)

101 if (Line.size() > ColumnLimit)

102 return true;

103 return false;

104}

105

106std::vector

107getRangesForFormatting(llvm::StringRef Code, unsigned ColumnLimit,

110

112 return {};

113 std::vectorclang::tooling::Range Ranges;

114

115

116

117 int Offset = 0;

119 int Start = R.getOffset() + Offset;

120 int End = Start + R.getReplacementText().size();

121 if (!R.getReplacementText().empty() &&

122 R.getReplacementText().back() == '\n' && R.getLength() == 0 &&

123 R.getOffset() > 0 && R.getOffset() <= Code.size() &&

124 Code[R.getOffset() - 1] == '\n')

125

126

127 --End;

128 Offset += R.getReplacementText().size() - R.getLength();

129

131 violatesColumnLimit(Code, ColumnLimit, Start, End))

132 Ranges.emplace_back(Start, End - Start);

133 }

134 return Ranges;

135}

136

137inline llvm::Error make_string_error(const llvm::Twine &Message) {

138 return llvm::make_errorllvm::StringError(Message,

139 llvm::inconvertibleErrorCode());

140}

141

142

144createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,

146 const format::FormatStyle &Style) {

147

148

149 Replacements HeaderReplacements;

150 for (const auto &Change : Changes) {

151 for (llvm::StringRef Header : Change.getInsertedHeaders()) {

152 std::string EscapedHeader =

153 Header.starts_with("<") || Header.starts_with("\"")

154 ? Header.str()

155 : ("\"" + Header + "\"").str();

156 std::string ReplacementText = "#include " + EscapedHeader;

157

158

159 llvm::Error Err = HeaderReplacements.add(

160 tooling::Replacement(FilePath, UINT_MAX, 0, ReplacementText));

161 if (Err)

162 return std::move(Err);

163 }

164 for (const std::string &Header : Change.getRemovedHeaders()) {

165

166

167 llvm::Error Err =

168 HeaderReplacements.add(Replacement(FilePath, UINT_MAX, 1, Header));

169 if (Err)

170 return std::move(Err);

171 }

172 }

173

174

175

177 Style);

178}

179

180

181

183combineReplacementsInChanges(llvm::StringRef FilePath,

185 Replacements Replaces;

186 for (const auto &Change : Changes)

187 for (const auto &R : Change.getReplacements())

188 if (auto Err = Replaces.add(Replacement(

189 FilePath, R.getOffset(), R.getLength(), R.getReplacementText())))

190 return std::move(Err);

191 return Replaces;

192}

193

194}

195

199 std::pair<FileID, unsigned> FileIDAndOffset =

202 assert(FE && "Cannot create AtomicChange with invalid location.");

203 FilePath = std::string(FE->getName());

204 Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);

205}

206

208 llvm::Any M)

210 Metadata = std::move(M);

211}

212

213AtomicChange::AtomicChange(std::string Key, std::string FilePath,

214 std::string Error,

215 std::vectorstd::string InsertedHeaders,

216 std::vectorstd::string RemovedHeaders,

218 : Key(std::move(Key)), FilePath(std::move(FilePath)),

219 Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),

220 RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {

221}

222

224 if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error)

225 return false;

226 if (!(Replaces == Other.Replaces))

227 return false;

228

229 return true;

230}

231

233 std::string YamlContent;

234 llvm::raw_string_ostream YamlContentStream(YamlContent);

235

236 llvm::yaml::Output YAML(YamlContentStream);

237 YAML << *this;

238 return YamlContent;

239}

240

242 NormalizedAtomicChange NE;

243 llvm::yaml::Input YAML(YAMLContent);

244 YAML >> NE;

245 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,

247 for (const auto &R : NE.Replaces) {

248 llvm::Error Err = E.Replaces.add(R);

249 if (Err)

250 llvm_unreachable(

251 "Failed to add replacement when Converting YAML to AtomicChange.");

252 llvm::consumeError(std::move(Err));

253 }

254 return E;

255}

256

259 llvm::StringRef ReplacementText) {

261}

262

264 unsigned Length, llvm::StringRef Text) {

266}

267

269 llvm::StringRef Text, bool InsertAfter) {

270 if (Text.empty())

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

273 llvm::Error Err = Replaces.add(R);

274 if (Err) {

275 return llvm::handleErrors(

276 std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {

278 return llvm::make_error(RE);

279 unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());

280 if (!InsertAfter)

281 NewOffset -=

284 Replaces = Replaces.merge(Replacements(NewR));

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

286 });

287 }

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

289}

290

292 InsertedHeaders.push_back(std::string(Header));

293}

294

296 RemovedHeaders.push_back(std::string(Header));

297}

298

304 createReplacementsForHeaders(FilePath, Code, Changes, Spec.Style);

305 if (!HeaderReplacements)

307 "Failed to create replacements for header changes: " +

308 llvm::toString(HeaderReplacements.takeError()));

309

311 combineReplacementsInChanges(FilePath, Changes);

312 if (!Replaces)

313 return make_string_error("Failed to combine replacements in all changes: " +

314 llvm::toString(Replaces.takeError()));

315

316 Replacements AllReplaces = std::move(*Replaces);

317 for (const auto &R : *HeaderReplacements) {

318 llvm::Error Err = AllReplaces.add(R);

319 if (Err)

321 "Failed to combine existing replacements with header replacements: " +

322 llvm::toString(std::move(Err)));

323 }

324

328 if (!CleanReplaces)

329 return make_string_error("Failed to cleanup around replacements: " +

330 llvm::toString(CleanReplaces.takeError()));

331 AllReplaces = std::move(*CleanReplaces);

332 }

333

334

337 if (!ChangedCode)

339 llvm::toString(ChangedCode.takeError()));

340

341

342

343

347 if (!ChangedCode)

349 "Failed to apply replacements for sorting includes: " +

350 llvm::toString(ChangedCode.takeError()));

351

352 AllReplaces = AllReplaces.merge(HeaderSortingReplacements);

353

354 std::vector FormatRanges = getRangesForFormatting(

356 if (!FormatRanges.empty()) {

360 if (!ChangedCode)

362 "Failed to apply replacements for formatting changed code: " +

363 llvm::toString(ChangedCode.takeError()));

364 }

365 return ChangedCode;

366}

367

368}

369}

This file defines the structure of a YAML document for serializing replacements.

Represents a character-granular source range.

StringRef getName() const

The name of this FileEntry.

A SourceLocation and its associated SourceManager.

FullSourceLoc getSpellingLoc() const

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

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

Encodes a location in the source.

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

Expected< tooling::Replacements > cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, const FormatStyle &Style)

Returns the replacements corresponding to applying Replaces and cleaning up the code after that on su...

tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, ArrayRef< tooling::Range > Ranges, StringRef FileName="", FormattingAttemptStatus *Status=nullptr)

Reformats the given Ranges in Code.

tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, ArrayRef< tooling::Range > Ranges, StringRef FileName, unsigned *Cursor=nullptr)

Returns the replacements necessary to sort all #include blocks that are affected by Ranges.

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

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))

@ Other

Other implicit parameter.

Diagnostic wrappers for TextAPI types for error reporting.

unsigned ColumnLimit

The column limit.

static void mapping(IO &Io, NormalizedAtomicChange &Doc)