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 &,

29 const clang::tooling::AtomicChange &E)

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

36 clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {

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

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,

109 const clang::tooling::Replacements &Replaces) {

110

112 return {};

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

114

115

116

117 int Offset = 0;

118 for (const clang::tooling::Replacement &R : Replaces) {

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

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 =

169 if (Err)

170 return std::move(Err);

171 }

172 }

173

174

175

177 Style);

178}

179

180

181

183combineReplacementsInChanges(llvm::StringRef FilePath,

186 for (const auto &Change : Changes)

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

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

190 return std::move(Err);

191 return Replaces;

192}

193

194}

195

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

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

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

204}

205

207 llvm::Any M)

209 Metadata = std::move(M);

210}

211

213 std::string Error,

214 std::vectorstd::string InsertedHeaders,

215 std::vectorstd::string RemovedHeaders,

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

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

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

220}

221

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

224 return false;

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

226 return false;

227

228 return true;

229}

230

232 std::string YamlContent;

233 llvm::raw_string_ostream YamlContentStream(YamlContent);

234

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

236 YAML << *this;

237 return YamlContent;

238}

239

241 NormalizedAtomicChange NE;

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

243 YAML >> NE;

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

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

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

248 if (Err)

249 llvm_unreachable(

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

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

252 }

253 return E;

254}

255

258 llvm::StringRef ReplacementText) {

260}

261

263 unsigned Length, llvm::StringRef Text) {

265}

266

268 llvm::StringRef Text, bool InsertAfter) {

269 if (Text.empty())

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

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

273 if (Err) {

274 return llvm::handleErrors(

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

277 return llvm::make_error(RE);

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

279 if (!InsertAfter)

280 NewOffset -=

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

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

285 });

286 }

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

288}

289

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

292}

293

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

296}

297

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

304 if (!HeaderReplacements)

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

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

308

310 combineReplacementsInChanges(FilePath, Changes);

311 if (!Replaces)

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

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

314

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

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

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

318 if (Err)

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

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

322 }

323

327 if (!CleanReplaces)

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

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

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

331 }

332

333

336 if (!ChangedCode)

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

339

340

341

342

346 if (!ChangedCode)

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

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

350

351 AllReplaces = AllReplaces.merge(HeaderSortingReplacements);

352

353 std::vector FormatRanges = getRangesForFormatting(

354 *ChangedCode, Spec.Style.ColumnLimit, Spec.Format, AllReplaces);

355 if (!FormatRanges.empty()) {

359 if (!ChangedCode)

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

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

363 }

364 return ChangedCode;

365}

366

367}

368}

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

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

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

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

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

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

CustomizableOptional< FileEntryRef > OptionalFileEntryRef

std::pair< FileID, unsigned > FileIDAndOffset

@ Other

Other implicit parameter.

Diagnostic wrappers for TextAPI types for error reporting.

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

Definition AtomicChange.cpp:55