24 #include "llvm/ADT/STLExtras.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/Support/Debug.h"
30 #define DEBUG_TYPE "format-formatter"
35 class FormatTokenLexer;
99 if (LHS.
Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT)
105 if (LHS.
URL.empty() != RHS.
URL.empty())
106 return LHS.
URL.empty() < RHS.
URL.empty();
107 if (
int Res = LHS.
URL.compare_lower(RHS.
URL))
124 FileContents(Env.getSourceManager().getBufferData(Env.getFileID())) {}
132 AnnotatedLines.end());
137 std::tie(References, FirstNonImportLine) =
138 parseModuleReferences(Keywords, AnnotatedLines);
140 if (References.empty())
144 for (
unsigned i = 0, e = References.size(); i != e; ++i)
145 Indices.push_back(i);
146 std::stable_sort(Indices.begin(), Indices.end(),
147 [&](
unsigned LHSI,
unsigned RHSI) {
148 return References[LHSI] < References[RHSI];
150 bool ReferencesInOrder = std::is_sorted(Indices.begin(), Indices.end());
152 std::string ReferencesText;
153 bool SymbolsInOrder =
true;
154 for (
unsigned i = 0, e = Indices.size(); i != e; ++i) {
156 if (appendReference(ReferencesText, Reference))
157 SymbolsInOrder =
false;
160 ReferencesText +=
"\n";
164 (Reference.
IsExport != References[Indices[i + 1]].IsExport ||
165 Reference.
Category != References[Indices[i + 1]].Category))
166 ReferencesText +=
"\n";
170 if (ReferencesInOrder && SymbolsInOrder)
174 InsertionPoint.
setEnd(References[References.size() - 1].Range.getEnd());
183 unsigned PreviousSize = getSourceText(InsertionPoint).size();
184 while (ReferencesText.size() < PreviousSize) {
185 ReferencesText +=
" ";
190 ReferencesText +=
"\n";
192 DEBUG(llvm::dbgs() <<
"Replacing imports:\n"
193 << getSourceText(InsertionPoint) <<
"\nwith:\n"
194 << ReferencesText <<
"\n");
214 StringRef FileContents;
216 void skipComments() { Current = skipComments(Current); }
218 FormatToken *skipComments(FormatToken *Tok) {
219 while (Tok && Tok->is(tok::comment))
225 Current = Current->
Next;
227 if (!Current || Current == LineEnd->
Next) {
231 Current = &invalidToken;
235 StringRef getSourceText(SourceRange Range) {
236 return getSourceText(Range.getBegin(), Range.getEnd());
239 StringRef getSourceText(SourceLocation
Begin, SourceLocation
End) {
241 return FileContents.substr(SM.getFileOffset(Begin),
242 SM.getFileOffset(End) - SM.getFileOffset(Begin));
247 bool appendReference(std::string &
Buffer, JsModuleReference &Reference) {
250 SmallVector<JsImportedSymbol, 1> Symbols = Reference.Symbols;
252 Symbols.begin(), Symbols.end(),
253 [&](
const JsImportedSymbol &LHS,
const JsImportedSymbol &RHS) {
254 return LHS.Symbol.compare_lower(RHS.Symbol) < 0;
256 if (Symbols == Reference.Symbols) {
258 StringRef ReferenceStmt = getSourceText(Reference.Range);
259 Buffer += ReferenceStmt;
263 SourceLocation SymbolsStart = Reference.Symbols.front().Range.getBegin();
264 SourceLocation SymbolsEnd = Reference.Symbols.back().Range.getEnd();
265 Buffer += getSourceText(Reference.Range.getBegin(), SymbolsStart);
267 for (
auto I = Symbols.begin(),
E = Symbols.end();
I !=
E; ++
I) {
268 if (
I != Symbols.begin())
270 Buffer += getSourceText(
I->Range);
273 Buffer += getSourceText(SymbolsEnd, Reference.Range.getEnd());
280 std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine*>
281 parseModuleReferences(
const AdditionalKeywords &
Keywords,
283 SmallVector<JsModuleReference, 16> References;
284 SourceLocation Start;
285 AnnotatedLine *FirstNonImportLine =
nullptr;
286 bool AnyImportAffected =
false;
287 for (
auto Line : AnnotatedLines) {
288 Current =
Line->First;
289 LineEnd =
Line->Last;
291 if (Start.isInvalid() || References.empty())
295 Start =
Line->First->Tok.getLocation();
298 FirstNonImportLine =
Line;
301 JsModuleReference Reference;
302 Reference.Range.setBegin(Start);
303 if (!parseModuleReference(Keywords, Reference)) {
304 if (!FirstNonImportLine)
305 FirstNonImportLine =
Line;
308 FirstNonImportLine =
nullptr;
309 AnyImportAffected = AnyImportAffected ||
Line->Affected;
312 llvm::dbgs() <<
"JsModuleReference: {"
313 <<
"is_export: " << Reference.IsExport
314 <<
", cat: " << Reference.Category
315 <<
", url: " << Reference.URL
316 <<
", prefix: " << Reference.Prefix;
317 for (
size_t i = 0; i < Reference.Symbols.size(); ++i)
318 llvm::dbgs() <<
", " << Reference.Symbols[i].Symbol <<
" as "
319 << Reference.Symbols[i].Alias;
320 llvm::dbgs() <<
", text: " << getSourceText(Reference.Range);
321 llvm::dbgs() <<
"}\n";
323 References.push_back(Reference);
324 Start = SourceLocation();
327 if (!AnyImportAffected)
329 return std::make_pair(References, FirstNonImportLine);
335 bool parseModuleReference(
const AdditionalKeywords &Keywords,
336 JsModuleReference &Reference) {
337 if (!Current || !Current->
isOneOf(Keywords.kw_import, tok::kw_export))
339 Reference.IsExport = Current->
is(tok::kw_export);
344 Reference.Category = JsModuleReference::ReferenceCategory::SIDE_EFFECT;
350 if (!parseModuleBindings(Keywords, Reference))
353 if (Current->
is(Keywords.kw_from)) {
361 if (Reference.URL.startswith(
".."))
363 JsModuleReference::ReferenceCategory::RELATIVE_PARENT;
364 else if (Reference.URL.startswith(
"."))
365 Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
367 Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE;
370 Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
375 bool parseModuleBindings(
const AdditionalKeywords &Keywords,
376 JsModuleReference &Reference) {
377 if (parseStarBinding(Keywords, Reference))
379 return parseNamedBindings(Keywords, Reference);
382 bool parseStarBinding(
const AdditionalKeywords &Keywords,
383 JsModuleReference &Reference) {
385 if (Current->
isNot(tok::star))
388 if (Current->
isNot(Keywords.kw_as))
391 if (Current->
isNot(tok::identifier))
398 bool parseNamedBindings(
const AdditionalKeywords &Keywords,
399 JsModuleReference &Reference) {
400 if (Current->
is(tok::identifier)) {
402 if (Current->
is(Keywords.kw_from))
404 if (Current->
isNot(tok::comma))
408 if (Current->
isNot(tok::l_brace))
412 while (Current->
isNot(tok::r_brace)) {
414 if (Current->
is(tok::r_brace))
416 if (Current->
isNot(tok::identifier))
419 JsImportedSymbol Symbol;
422 Symbol.Range.setBegin(
426 if (Current->
is(Keywords.kw_as)) {
428 if (Current->
isNot(tok::identifier))
434 Reference.Symbols.push_back(Symbol);
436 if (!Current->
isOneOf(tok::r_brace, tok::comma))
449 std::unique_ptr<Environment> Env =
Defines the SourceManager interface.
std::unique_ptr< llvm::MemoryBuffer > Buffer
This file implements a token annotator, i.e.
void setKind(tok::TokenKind K)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Defines the Diagnostic-related interfaces.
detail::InMemoryDirectory::const_iterator I
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEndLoc() const
ArrayRef< FormatToken * > Tokens
SourceLocation getBegin() const
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
This file implements a sorter for JavaScript ES6 imports.
detail::InMemoryDirectory::const_iterator E
std::string toString(const til::SExpr *E)
This file declares an abstract TokenAnalyzer, and associated helper classes.
Defines the clang::SourceLocation class and associated facilities.
void setEnd(SourceLocation e)
A trivial tuple used to represent a source range.