14967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//===--- SortJavaScriptImports.h - Sort ES6 Imports -------------*- C++ -*-===//
24967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
34967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//                     The LLVM Compiler Infrastructure
44967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
54967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// This file is distributed under the University of Illinois Open Source
64967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// License. See LICENSE.TXT for details.
74967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
84967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//===----------------------------------------------------------------------===//
94967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar///
104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// \file
114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// \brief This file implements a sort operation for JavaScript ES6 imports.
124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar///
134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//===----------------------------------------------------------------------===//
144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "SortJavaScriptImports.h"
164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "SortJavaScriptImports.h"
174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "TokenAnalyzer.h"
184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "TokenAnnotator.h"
194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Basic/Diagnostic.h"
204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Basic/DiagnosticOptions.h"
214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Basic/LLVM.h"
224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Basic/SourceLocation.h"
234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Basic/SourceManager.h"
244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/Format/Format.h"
254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "llvm/ADT/STLExtras.h"
264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "llvm/ADT/SmallVector.h"
274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "llvm/Support/Debug.h"
284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include <algorithm>
294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include <string>
304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#define DEBUG_TYPE "format-formatter"
324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarnamespace clang {
344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarnamespace format {
354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarclass FormatTokenLexer;
374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarusing clang::format::FormatStyle;
394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// An imported symbol in a JavaScript ES6 import/export, possibly aliased.
414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarstruct JsImportedSymbol {
424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef Symbol;
434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef Alias;
444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  SourceRange Range;
454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool operator==(const JsImportedSymbol &RHS) const {
474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // Ignore Range for comparison, it is only used to stitch code together,
484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // but imports at different code locations are still conceptually the same.
494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return Symbol == RHS.Symbol && Alias == RHS.Alias;
504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar};
524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// An ES6 module reference.
544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// ES6 implements a module system, where individual modules (~= source files)
564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// can reference other modules, either importing symbols from them, or exporting
574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// symbols from them:
584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//   import {foo} from 'foo';
594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//   export {foo};
604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//   export {bar} from 'bar';
614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// `export`s with URLs are syntactic sugar for an import of the symbol from the
634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// URL, followed by an export of the symbol, allowing this code to treat both
644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// statements more or less identically, with the exception being that `export`s
654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// are sorted last.
664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// imports and exports support individual symbols, but also a wildcard syntax:
684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//   import * as prefix from 'foo';
694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//   export * from 'bar';
704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar//
714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// This struct represents both exports and imports to build up the information
724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// required for sorting module references.
734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarstruct JsModuleReference {
744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool IsExport = false;
754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Module references are sorted into these categories, in order.
764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  enum ReferenceCategory {
774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SIDE_EFFECT,     // "import 'something';"
784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    ABSOLUTE,        // from 'something'
794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    RELATIVE_PARENT, // from '../*'
804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    RELATIVE,        // from './*'
814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  };
824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  ReferenceCategory Category = ReferenceCategory::SIDE_EFFECT;
834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // The URL imported, e.g. `import .. from 'url';`. Empty for `export {a, b};`.
844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef URL;
854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Prefix from "import * as prefix". Empty for symbol imports and `export *`.
864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Implies an empty names list.
874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef Prefix;
884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Symbols from `import {SymbolA, SymbolB, ...} from ...;`.
894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  SmallVector<JsImportedSymbol, 1> Symbols;
904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Textual position of the import/export, including preceding and trailing
914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // comments.
924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  SourceRange Range;
934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar};
944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool operator<(const JsModuleReference &LHS, const JsModuleReference &RHS) {
964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.IsExport != RHS.IsExport)
974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return LHS.IsExport < RHS.IsExport;
984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.Category != RHS.Category)
994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return LHS.Category < RHS.Category;
1004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT)
1014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // Side effect imports might be ordering sensitive. Consider them equal so
1024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // that they maintain their relative order in the stable sort below.
1034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // This retains transitivity because LHS.Category == RHS.Category here.
1044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return false;
1054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Empty URLs sort *last* (for export {...};).
1064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.URL.empty() != RHS.URL.empty())
1074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return LHS.URL.empty() < RHS.URL.empty();
1084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (int Res = LHS.URL.compare_lower(RHS.URL))
1094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return Res < 0;
1104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // '*' imports (with prefix) sort before {a, b, ...} imports.
1114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.Prefix.empty() != RHS.Prefix.empty())
1124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return LHS.Prefix.empty() < RHS.Prefix.empty();
1134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (LHS.Prefix != RHS.Prefix)
1144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return LHS.Prefix > RHS.Prefix;
1154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  return false;
1164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
1174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// JavaScriptImportSorter sorts JavaScript ES6 imports and exports. It is
1194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// implemented as a TokenAnalyzer because ES6 imports have substantial syntactic
1204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// structure, making it messy to sort them using regular expressions.
1214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarclass JavaScriptImportSorter : public TokenAnalyzer {
1224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarpublic:
1234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  JavaScriptImportSorter(const Environment &Env, const FormatStyle &Style)
1244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      : TokenAnalyzer(Env, Style),
1254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        FileContents(Env.getSourceManager().getBufferData(Env.getFileID())) {}
1264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  tooling::Replacements
1284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  analyze(TokenAnnotator &Annotator,
1294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          FormatTokenLexer &Tokens, tooling::Replacements &Result) override {
1314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
1324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                                          AnnotatedLines.end());
1334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    const AdditionalKeywords &Keywords = Tokens.getKeywords();
1354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SmallVector<JsModuleReference, 16> References;
1364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    AnnotatedLine *FirstNonImportLine;
1374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    std::tie(References, FirstNonImportLine) =
1384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        parseModuleReferences(Keywords, AnnotatedLines);
1394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (References.empty())
1414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return Result;
1424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SmallVector<unsigned, 16> Indices;
1444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    for (unsigned i = 0, e = References.size(); i != e; ++i)
1454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Indices.push_back(i);
1464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    std::stable_sort(Indices.begin(), Indices.end(),
1474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     [&](unsigned LHSI, unsigned RHSI) {
1484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                       return References[LHSI] < References[RHSI];
1494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     });
1504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    bool ReferencesInOrder = std::is_sorted(Indices.begin(), Indices.end());
1514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    std::string ReferencesText;
1534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    bool SymbolsInOrder = true;
1544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
1554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      JsModuleReference Reference = References[Indices[i]];
1564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (appendReference(ReferencesText, Reference))
1574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        SymbolsInOrder = false;
1584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (i + 1 < e) {
1594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // Insert breaks between imports and exports.
1604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        ReferencesText += "\n";
1614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // Separate imports groups with two line breaks, but keep all exports
1624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // in a single group.
1634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if (!Reference.IsExport &&
1644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            (Reference.IsExport != References[Indices[i + 1]].IsExport ||
1654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar             Reference.Category != References[Indices[i + 1]].Category))
1664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          ReferencesText += "\n";
1674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      }
1684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (ReferencesInOrder && SymbolsInOrder)
1714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return Result;
1724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SourceRange InsertionPoint = References[0].Range;
1744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    InsertionPoint.setEnd(References[References.size() - 1].Range.getEnd());
1754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // The loop above might collapse previously existing line breaks between
1774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // import blocks, and thus shrink the file. SortIncludes must not shrink
1784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // overall source length as there is currently no re-calculation of ranges
1794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // after applying source sorting.
1804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // This loop just backfills trailing spaces after the imports, which are
1814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // harmless and will be stripped by the subsequent formatting pass.
1824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // FIXME: A better long term fix is to re-calculate Ranges after sorting.
1834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    unsigned PreviousSize = getSourceText(InsertionPoint).size();
1844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    while (ReferencesText.size() < PreviousSize) {
1854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      ReferencesText += " ";
1864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // Separate references from the main code body of the file.
1894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (FirstNonImportLine && FirstNonImportLine->First->NewlinesBefore < 2)
1904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      ReferencesText += "\n";
1914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    DEBUG(llvm::dbgs() << "Replacing imports:\n"
1934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                       << getSourceText(InsertionPoint) << "\nwith:\n"
1944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                       << ReferencesText << "\n");
1954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Result.insert(tooling::Replacement(
1964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Env.getSourceManager(), CharSourceRange::getCharRange(InsertionPoint),
1974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        ReferencesText));
1984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return Result;
2004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarprivate:
2034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  FormatToken *Current;
2044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  FormatToken *LineEnd;
2054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  FormatToken invalidToken;
2074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef FileContents;
2094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  void skipComments() { Current = skipComments(Current); }
2114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  FormatToken *skipComments(FormatToken *Tok) {
2134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    while (Tok && Tok->is(tok::comment))
2144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Tok = Tok->Next;
2154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return Tok;
2164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  void nextToken() {
2194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Current = Current->Next;
2204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    skipComments();
2214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (!Current || Current == LineEnd->Next) {
2224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // Set the current token to an invalid token, so that further parsing on
2234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // this line fails.
2244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      invalidToken.Tok.setKind(tok::unknown);
2254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Current = &invalidToken;
2264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
2274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef getSourceText(SourceRange Range) {
2304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return getSourceText(Range.getBegin(), Range.getEnd());
2314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  StringRef getSourceText(SourceLocation Begin, SourceLocation End) {
2344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    const SourceManager &SM = Env.getSourceManager();
2354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return FileContents.substr(SM.getFileOffset(Begin),
2364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                               SM.getFileOffset(End) - SM.getFileOffset(Begin));
2374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Appends ``Reference`` to ``Buffer``, returning true if text within the
2404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // ``Reference`` changed (e.g. symbol order).
2414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool appendReference(std::string &Buffer, JsModuleReference &Reference) {
2424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // Sort the individual symbols within the import.
2434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';`
2444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SmallVector<JsImportedSymbol, 1> Symbols = Reference.Symbols;
2454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    std::stable_sort(
2464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Symbols.begin(), Symbols.end(),
2474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        [&](const JsImportedSymbol &LHS, const JsImportedSymbol &RHS) {
2484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          return LHS.Symbol.compare_lower(RHS.Symbol) < 0;
2494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        });
2504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Symbols == Reference.Symbols) {
2514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // No change in symbol order.
2524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      StringRef ReferenceStmt = getSourceText(Reference.Range);
2534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Buffer += ReferenceStmt;
2544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
2554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
2564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // Stitch together the module reference start...
2574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SourceLocation SymbolsStart = Reference.Symbols.front().Range.getBegin();
2584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SourceLocation SymbolsEnd = Reference.Symbols.back().Range.getEnd();
2594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Buffer += getSourceText(Reference.Range.getBegin(), SymbolsStart);
2604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // ... then the references in order ...
2614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
2624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (I != Symbols.begin())
2634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Buffer += ",";
2644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Buffer += getSourceText(I->Range);
2654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
2664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // ... followed by the module reference end.
2674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Buffer += getSourceText(SymbolsEnd, Reference.Range.getEnd());
2684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return true;
2694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
2704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
2714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Parses module references in the given lines. Returns the module references,
2724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // and a pointer to the first "main code" line if that is adjacent to the
2734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // affected lines of module references, nullptr otherwise.
2744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine*>
2754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  parseModuleReferences(const AdditionalKeywords &Keywords,
2764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                        SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
2774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SmallVector<JsModuleReference, 16> References;
2784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SourceLocation Start;
2794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    bool FoundLines = false;
2804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    AnnotatedLine *FirstNonImportLine = nullptr;
2814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    for (auto Line : AnnotatedLines) {
2824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (!Line->Affected) {
2834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // Only sort the first contiguous block of affected lines.
2844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if (FoundLines)
2854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          break;
2864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        else
2874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          continue;
2884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      }
2894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Current = Line->First;
2904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      LineEnd = Line->Last;
2914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      skipComments();
2924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Start.isInvalid() || References.empty())
2934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // After the first file level comment, consider line comments to be part
2944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // of the import that immediately follows them by using the previously
2954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        // set Start.
2964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Start = Line->First->Tok.getLocation();
2974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (!Current)
2984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        continue; // Only comments on this line.
2994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      FoundLines = true;
3004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      JsModuleReference Reference;
3014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.Range.setBegin(Start);
3024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (!parseModuleReference(Keywords, Reference)) {
3034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        FirstNonImportLine = Line;
3044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        break;
3054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      }
3064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.Range.setEnd(LineEnd->Tok.getEndLoc());
3074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      DEBUG({
3084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        llvm::dbgs() << "JsModuleReference: {"
3094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     << "is_export: " << Reference.IsExport
3104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     << ", cat: " << Reference.Category
3114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     << ", url: " << Reference.URL
3124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                     << ", prefix: " << Reference.Prefix;
3134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        for (size_t i = 0; i < Reference.Symbols.size(); ++i)
3144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          llvm::dbgs() << ", " << Reference.Symbols[i].Symbol << " as "
3154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                       << Reference.Symbols[i].Alias;
3164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        llvm::dbgs() << ", text: " << getSourceText(Reference.Range);
3174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        llvm::dbgs() << "}\n";
3184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      });
3194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      References.push_back(Reference);
3204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Start = SourceLocation();
3214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
3224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return std::make_pair(References, FirstNonImportLine);
3234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
3244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // Parses a JavaScript/ECMAScript 6 module reference.
3264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // See http://www.ecma-international.org/ecma-262/6.0/#sec-scripts-and-modules
3274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // for grammar EBNF (production ModuleItem).
3284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool parseModuleReference(const AdditionalKeywords &Keywords,
3294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                            JsModuleReference &Reference) {
3304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (!Current || !Current->isOneOf(Keywords.kw_import, tok::kw_export))
3314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Reference.IsExport = Current->is(tok::kw_export);
3334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    nextToken();
3354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->isStringLiteral() && !Reference.IsExport) {
3364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // "import 'side-effect';"
3374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.Category = JsModuleReference::ReferenceCategory::SIDE_EFFECT;
3384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.URL =
3394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          Current->TokenText.substr(1, Current->TokenText.size() - 2);
3404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return true;
3414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
3424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (!parseModuleBindings(Keywords, Reference))
3444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    nextToken();
3464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->is(Keywords.kw_from)) {
3484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // imports have a 'from' clause, exports might not.
3494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      nextToken();
3504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (!Current->isStringLiteral())
3514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return false;
3524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // URL = TokenText without the quotes.
3534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.URL =
3544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          Current->TokenText.substr(1, Current->TokenText.size() - 2);
3554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Reference.URL.startswith(".."))
3564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Reference.Category =
3574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            JsModuleReference::ReferenceCategory::RELATIVE_PARENT;
3584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      else if (Reference.URL.startswith("."))
3594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
3604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      else
3614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE;
3624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    } else {
3634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // w/o URL groups with "empty".
3644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE;
3654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
3664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return true;
3674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
3684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool parseModuleBindings(const AdditionalKeywords &Keywords,
3704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                           JsModuleReference &Reference) {
3714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (parseStarBinding(Keywords, Reference))
3724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return true;
3734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return parseNamedBindings(Keywords, Reference);
3744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
3754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool parseStarBinding(const AdditionalKeywords &Keywords,
3774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                        JsModuleReference &Reference) {
3784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // * as prefix from '...';
3794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->isNot(tok::star))
3804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    nextToken();
3824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->isNot(Keywords.kw_as))
3834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    nextToken();
3854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->isNot(tok::identifier))
3864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Reference.Prefix = Current->TokenText;
3884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return true;
3894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
3904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  bool parseNamedBindings(const AdditionalKeywords &Keywords,
3924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                          JsModuleReference &Reference) {
3934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if (Current->isNot(tok::l_brace))
3944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      return false;
3954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    // {sym as alias, sym2 as ...} from '...';
3974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    nextToken();
3984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    while (true) {
3994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Current->is(tok::r_brace))
4004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return true;
4014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Current->isNot(tok::identifier))
4024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return false;
4034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      JsImportedSymbol Symbol;
4054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Symbol.Symbol = Current->TokenText;
4064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      // Make sure to include any preceding comments.
4074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Symbol.Range.setBegin(
4084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          Current->getPreviousNonComment()->Next->WhitespaceRange.getBegin());
4094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      nextToken();
4104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Current->is(Keywords.kw_as)) {
4124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        nextToken();
4134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if (Current->isNot(tok::identifier))
4144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          return false;
4154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Symbol.Alias = Current->TokenText;
4164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        nextToken();
4174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      }
4184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Symbol.Range.setEnd(Current->Tok.getLocation());
4194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Reference.Symbols.push_back(Symbol);
4204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Current->is(tok::r_brace))
4224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return true;
4234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if (Current->isNot(tok::comma))
4244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return false;
4254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      nextToken();
4264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
4274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  }
4284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar};
4294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainartooling::Replacements sortJavaScriptImports(const FormatStyle &Style,
4314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                                            StringRef Code,
4324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                                            ArrayRef<tooling::Range> Ranges,
4334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                                            StringRef FileName) {
4344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  // FIXME: Cursor support.
4354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  std::unique_ptr<Environment> Env =
4364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
4374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  JavaScriptImportSorter Sorter(*Env, Style);
4384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  return Sorter.process();
4394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
4404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} // end namespace format
4424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} // end namespace clang
443