25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallVector.h"
27 #include "llvm/Support/Debug.h"
31 #define DEBUG_TYPE "format-formatter"
36 class FormatTokenLexer;
100 if (LHS.
Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT)
106 if (LHS.
URL.empty() != RHS.
URL.empty())
107 return LHS.
URL.empty() < RHS.
URL.empty();
108 if (
int Res = LHS.
URL.compare_lower(RHS.
URL))
125 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");
208 StringRef FileContents;
210 void skipComments() { Current = skipComments(Current); }
212 FormatToken *skipComments(FormatToken *Tok) {
213 while (Tok && Tok->is(tok::comment))
219 Current = Current->
Next;
221 if (!Current || Current == LineEnd->
Next) {
225 Current = &invalidToken;
229 StringRef getSourceText(SourceRange Range) {
230 return getSourceText(Range.getBegin(), Range.getEnd());
233 StringRef getSourceText(SourceLocation Begin, SourceLocation
End) {
235 return FileContents.substr(SM.getFileOffset(Begin),
236 SM.getFileOffset(End) - SM.getFileOffset(Begin));
241 bool appendReference(std::string &
Buffer, JsModuleReference &Reference) {
244 SmallVector<JsImportedSymbol, 1> Symbols = Reference.Symbols;
246 Symbols.begin(), Symbols.end(),
247 [&](
const JsImportedSymbol &LHS,
const JsImportedSymbol &RHS) {
248 return LHS.Symbol.compare_lower(RHS.Symbol) < 0;
250 if (Symbols == Reference.Symbols) {
252 StringRef ReferenceStmt = getSourceText(Reference.Range);
253 Buffer += ReferenceStmt;
257 SourceLocation SymbolsStart = Reference.Symbols.front().Range.getBegin();
258 SourceLocation SymbolsEnd = Reference.Symbols.back().Range.getEnd();
259 Buffer += getSourceText(Reference.Range.getBegin(), SymbolsStart);
261 for (
auto I = Symbols.begin(),
E = Symbols.end();
I !=
E; ++
I) {
262 if (
I != Symbols.begin())
264 Buffer += getSourceText(
I->Range);
267 Buffer += getSourceText(SymbolsEnd, Reference.Range.getEnd());
274 std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine*>
275 parseModuleReferences(
const AdditionalKeywords &
Keywords,
276 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
277 SmallVector<JsModuleReference, 16> References;
278 SourceLocation Start;
279 bool FoundLines =
false;
280 AnnotatedLine *FirstNonImportLine =
nullptr;
281 for (
auto Line : AnnotatedLines) {
282 if (!
Line->Affected) {
289 Current =
Line->First;
290 LineEnd =
Line->Last;
292 if (Start.isInvalid() || References.empty())
296 Start =
Line->First->Tok.getLocation();
300 JsModuleReference Reference;
301 Reference.Range.setBegin(Start);
302 if (!parseModuleReference(Keywords, Reference)) {
303 FirstNonImportLine =
Line;
308 llvm::dbgs() <<
"JsModuleReference: {"
309 <<
"is_export: " << Reference.IsExport
310 <<
", cat: " << Reference.Category
311 <<
", url: " << Reference.URL
312 <<
", prefix: " << Reference.Prefix;
313 for (
size_t i = 0; i < Reference.Symbols.size(); ++i)
314 llvm::dbgs() <<
", " << Reference.Symbols[i].Symbol <<
" as "
315 << Reference.Symbols[i].Alias;
316 llvm::dbgs() <<
", text: " << getSourceText(Reference.Range);
317 llvm::dbgs() <<
"}\n";
319 References.push_back(Reference);
320 Start = SourceLocation();
322 return std::make_pair(References, FirstNonImportLine);
328 bool parseModuleReference(
const AdditionalKeywords &Keywords,
329 JsModuleReference &Reference) {
330 if (!Current || !Current->
isOneOf(Keywords.kw_import, tok::kw_export))
332 Reference.IsExport = Current->
is(tok::kw_export);
337 Reference.Category = JsModuleReference::ReferenceCategory::SIDE_EFFECT;
343 if (!parseModuleBindings(Keywords, Reference))
347 if (Current->
is(Keywords.kw_from)) {
355 if (Reference.URL.startswith(
".."))
357 JsModuleReference::ReferenceCategory::RELATIVE_PARENT;
358 else if (Reference.URL.startswith(
"."))
359 Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
361 Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE;
364 Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
369 bool parseModuleBindings(
const AdditionalKeywords &Keywords,
370 JsModuleReference &Reference) {
371 if (parseStarBinding(Keywords, Reference))
373 return parseNamedBindings(Keywords, Reference);
376 bool parseStarBinding(
const AdditionalKeywords &Keywords,
377 JsModuleReference &Reference) {
379 if (Current->
isNot(tok::star))
382 if (Current->
isNot(Keywords.kw_as))
385 if (Current->
isNot(tok::identifier))
391 bool parseNamedBindings(
const AdditionalKeywords &Keywords,
392 JsModuleReference &Reference) {
393 if (Current->
isNot(tok::l_brace))
399 if (Current->
is(tok::r_brace))
401 if (Current->
isNot(tok::identifier))
404 JsImportedSymbol Symbol;
407 Symbol.Range.setBegin(
411 if (Current->
is(Keywords.kw_as)) {
413 if (Current->
isNot(tok::identifier))
419 Reference.Symbols.push_back(Symbol);
421 if (Current->
is(tok::r_brace))
423 if (Current->
isNot(tok::comma))
435 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...
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.
const AdditionalKeywords & Keywords
detail::InMemoryDirectory::const_iterator E
Defines the Diagnostic-related interfaces.
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.