[PATCH] D150116: clang-format: [JS] support import/export type
jankuehle created this revision. jankuehle added a project: clang-format. Herald added projects: All, clang. Herald added a subscriber: cfe-commits. Herald added reviewers: rymiel, HazardyKnusperkeks, owenpan, MyDeveloperDay. jankuehle requested review of this revision. Users can choose to only import/export the type of the symbol (not value nor namespace) by adding a `type` keyword, e.g.: import type {x} from 'y'; import {type x} from 'y'; export type {x}; export {type x}; Previously, this was not handled and would: - Terminate import sorting - Remove the space before the curly bracket in `export type {` With this change, both formatting and import sorting work as expected. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D150116 Files: clang/lib/Format/SortJavaScriptImports.cpp clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/FormatTestJS.cpp clang/unittests/Format/SortImportsTestJS.cpp Index: clang/unittests/Format/SortImportsTestJS.cpp === --- clang/unittests/Format/SortImportsTestJS.cpp +++ clang/unittests/Format/SortImportsTestJS.cpp @@ -465,6 +465,46 @@ "console.log(Z);\n"); } +TEST_F(SortImportsTestJS, ImportExportType) { + verifySort("import type {sym} from 'a';\n" + "import {type sym} from 'b';\n" + "import {sym} from 'c';\n" + "import type sym from 'd';\n" + "import type * as sym from 'e';\n" + "\n" + "let x = 1;", + "import {sym} from 'c';\n" + "import type {sym} from 'a';\n" + "import type * as sym from 'e';\n" + "import type sym from 'd';\n" + "import {type sym} from 'b';\n" + "let x = 1;"); + + // Symbols within import statement + verifySort("import {type sym1, type sym2 as a, sym3} from 'b';\n", + "import {type sym2 as a, type sym1, sym3} from 'b';\n"); + + // Merging + verifySort("import {X, type Z} from 'a';\n" + "import type {Y} from 'a';\n" + "\n" + "X + Y + Z;\n", + "import {X} from 'a';\n" + "import {type Z} from 'a';\n" + "import type {Y} from 'a';\n" + "\n" + "X + Y + Z;\n"); + + // Merging: empty imports + verifySort("import type {A} from 'foo';\n", "import type {} from 'foo';\n" + "import type {A} from 'foo';"); + + // Merging: exports + verifySort("export {A, type B} from 'foo';\n", + "export {A} from 'foo';\n" + "export {type B} from 'foo';"); +} + } // end namespace } // end namespace format } // end namespace clang Index: clang/unittests/Format/FormatTestJS.cpp === --- clang/unittests/Format/FormatTestJS.cpp +++ clang/unittests/Format/FormatTestJS.cpp @@ -1476,6 +1476,17 @@ " export class Y {}"); } +TEST_F(FormatTestJS, ImportExportType) { + verifyFormat("import type {x, y} from 'y';\n" + "import type * as x from 'y';\n" + "import type x from 'y';\n" + "import {x, type yu, z} from 'y';\n"); + verifyFormat("export type {x, y} from 'y';\n" + "export {x, type yu, z} from 'y';\n" + "export type {x, y};\n" + "export {x, type yu, z};\n"); +} + TEST_F(FormatTestJS, ClosureStyleCasts) { verifyFormat("var x = /** @type {foo} */ (bar);"); } Index: clang/lib/Format/UnwrappedLineParser.cpp === --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -4068,7 +4068,9 @@ // parsing the structural element, i.e. the declaration or expression for // `export default`. if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) && - !FormatTok->isStringLiteral()) { + !FormatTok->isStringLiteral() && + !(FormatTok->is(Keywords.kw_type) && +Tokens->peekNextToken()->isOneOf(tok::l_brace, tok::star))) { return; } Index: clang/lib/Format/SortJavaScriptImports.cpp === --- clang/lib/Format/SortJavaScriptImports.cpp +++ clang/lib/Format/SortJavaScriptImports.cpp @@ -72,6 +72,7 @@ struct JsModuleReference { bool FormattingOff = false; bool IsExport = false; + bool IsTypeOnly = false; // Module references are sorted into these categories, in order. enum ReferenceCategory { SIDE_EFFECT, // "import 'something';" @@ -306,6 +307,7 @@ if (Reference->Category == JsModuleReference::SIDE_EFFECT || PreviousReference->Category == JsModuleReference::SIDE_EFFECT || Reference->IsExport != PreviousReference->IsExport || + Reference->IsTypeOnly != PreviousReference->IsTypeOnly || !PreviousReference->Prefix.empty(
[PATCH] D150563: clang-format: [JS] terminate import sorting on `export type X = Y`
jankuehle created this revision. jankuehle added projects: clang, clang-format. Herald added a project: All. Herald added a subscriber: cfe-commits. Herald added reviewers: rymiel, HazardyKnusperkeks, owenpan, MyDeveloperDay. jankuehle requested review of this revision. https://reviews.llvm.org/D150116 introduced a bug. `export type X = Y` was considered an export declaration and took part in import sorting. This is not correct. With this change `export type X = Y` properly terminates import sorting. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D150563 Files: clang/lib/Format/SortJavaScriptImports.cpp clang/unittests/Format/SortImportsTestJS.cpp Index: clang/unittests/Format/SortImportsTestJS.cpp === --- clang/unittests/Format/SortImportsTestJS.cpp +++ clang/unittests/Format/SortImportsTestJS.cpp @@ -503,6 +503,15 @@ verifySort("export {A, type B} from 'foo';\n", "export {A} from 'foo';\n" "export {type B} from 'foo';"); + + // `export type X = Y;` should terminate import sorting. The following export + // statements should therefore not merge. + verifySort("export type A = B;\n" + "export {X};\n" + "export {Y};\n", + "export type A = B;\n" + "export {X};\n" + "export {Y};\n"); } } // end namespace Index: clang/lib/Format/SortJavaScriptImports.cpp === --- clang/lib/Format/SortJavaScriptImports.cpp +++ clang/lib/Format/SortJavaScriptImports.cpp @@ -517,7 +517,7 @@ } // eat a potential "import X, " prefix. -if (Current->is(tok::identifier)) { +if (!Reference.IsExport && Current->is(tok::identifier)) { Reference.DefaultImport = Current->TokenText; nextToken(); if (Current->is(Keywords.kw_from)) Index: clang/unittests/Format/SortImportsTestJS.cpp === --- clang/unittests/Format/SortImportsTestJS.cpp +++ clang/unittests/Format/SortImportsTestJS.cpp @@ -503,6 +503,15 @@ verifySort("export {A, type B} from 'foo';\n", "export {A} from 'foo';\n" "export {type B} from 'foo';"); + + // `export type X = Y;` should terminate import sorting. The following export + // statements should therefore not merge. + verifySort("export type A = B;\n" + "export {X};\n" + "export {Y};\n", + "export type A = B;\n" + "export {X};\n" + "export {Y};\n"); } } // end namespace Index: clang/lib/Format/SortJavaScriptImports.cpp === --- clang/lib/Format/SortJavaScriptImports.cpp +++ clang/lib/Format/SortJavaScriptImports.cpp @@ -517,7 +517,7 @@ } // eat a potential "import X, " prefix. -if (Current->is(tok::identifier)) { +if (!Reference.IsExport && Current->is(tok::identifier)) { Reference.DefaultImport = Current->TokenText; nextToken(); if (Current->is(Keywords.kw_from)) ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D108692: [clang-format] Support TypeScript override keyword
jankuehle created this revision. jankuehle requested review of this revision. Herald added a project: clang. TypeScript 4.3 added a new "override" keyword for class members. This lets clang-format know about it, so it can format code using it properly. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D108692 Files: clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.cpp clang/lib/Format/UnwrappedLineFormatter.cpp clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/FormatTestJS.cpp Index: clang/unittests/Format/FormatTestJS.cpp === --- clang/unittests/Format/FormatTestJS.cpp +++ clang/unittests/Format/FormatTestJS.cpp @@ -854,6 +854,26 @@ "}\n"); } +TEST_F(FormatTestJS, OverriddenMembers) { + verifyFormat( + "class C extends P {\n" + " protected override " + "anOverlyLongPropertyNameSoLongItHasToGoInASeparateLineWhenOverriden:\n" + " undefined;\n" + "}\n"); + verifyFormat( + "class C extends P {\n" + " protected override " + "anOverlyLongMethodNameSoLongItHasToGoInASeparateLineWhenOverriden() {\n" + " }\n" + "}\n"); + verifyFormat("class C extends P {\n" + " protected override aMethodName() {}\n" + "}\n"); +} + TEST_F(FormatTestJS, FunctionParametersTrailingComma) { verifyFormat("function trailingComma(\n" "p1,\n" Index: clang/lib/Format/UnwrappedLineParser.cpp === --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -962,8 +962,8 @@ Keywords.kw_function, Keywords.kw_import, Keywords.kw_is, Keywords.kw_let, Keywords.kw_var, tok::kw_const, Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements, - Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws, - Keywords.kw_from)); + Keywords.kw_instanceof, Keywords.kw_interface, + Keywords.kw_override, Keywords.kw_throws, Keywords.kw_from)); } static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, Index: clang/lib/Format/UnwrappedLineFormatter.cpp === --- clang/lib/Format/UnwrappedLineFormatter.cpp +++ clang/lib/Format/UnwrappedLineFormatter.cpp @@ -632,10 +632,11 @@ FormatToken *RecordTok = Line.First; // Skip record modifiers. while (RecordTok->Next && - RecordTok->isOneOf( - tok::kw_typedef, tok::kw_export, Keywords.kw_declare, - Keywords.kw_abstract, tok::kw_default, tok::kw_public, - tok::kw_private, tok::kw_protected, Keywords.kw_internal)) + RecordTok->isOneOf(tok::kw_typedef, tok::kw_export, + Keywords.kw_declare, Keywords.kw_abstract, + tok::kw_default, Keywords.kw_override, + tok::kw_public, tok::kw_private, + tok::kw_protected, Keywords.kw_internal)) RecordTok = RecordTok->Next; if (RecordTok && RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, Index: clang/lib/Format/TokenAnnotator.cpp === --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3957,8 +3957,9 @@ tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected, -Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get, -Keywords.kw_set, Keywords.kw_async, Keywords.kw_await)) +Keywords.kw_readonly, Keywords.kw_override, Keywords.kw_abstract, +Keywords.kw_get, Keywords.kw_set, Keywords.kw_async, +Keywords.kw_await)) return false; // Otherwise automatic semicolon insertion would trigger. if (Right.NestingLevel == 0 && (Left.Tok.getIdentifierInfo() || Index: clang/lib/Format/FormatToken.h === --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -934,8 +934,8 @@ // already initialized. JsExtraKeywords = std::unordered_set( {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, - kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, - kw_set, kw_type, kw_typeof, kw_var, kw_yield, + kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_override, + kw_readonly, kw_set, kw_type, kw_typeof, kw_var, kw_yield, // Keywords from the Java section. kw_abstra
[PATCH] D108692: [clang-format] Support TypeScript override keyword
jankuehle added a comment. Thank you for the amazingly quick review, krasimir. I don't have commit access. So it would be great, if you could commit this for me. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108692/new/ https://reviews.llvm.org/D108692 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits