Index: lib/Format/FormatTokenLexer.cpp =================================================================== --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -20,6 +20,10 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "format-formatter" + namespace clang { namespace format { @@ -52,6 +56,7 @@ tryParseTemplateString(); } tryMergePreviousTokens(); + if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline) FirstInLineIndex = Tokens.size() - 1; } while (Tokens.back()->Tok.isNot(tok::eof)); Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -694,6 +694,19 @@ next(); if (!CurrentToken) return Type; + + if (Style.Language == FormatStyle::LK_JavaScript) { + // JavaScript files can contain shebang lines of the form: + // #!/usr/bin/env node + // Treat these like C++ #include directives. + while (CurrentToken) { + // Tokens cannot be comments here. + CurrentToken->Type = TT_ImplicitStringLiteral; + next(); + } + return LT_ImportStatement; + } + if (CurrentToken->Tok.is(tok::numeric_constant)) { CurrentToken->SpacesRequiredBefore = 1; return Type; Index: unittests/Format/FormatTestJS.cpp =================================================================== --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1272,5 +1272,12 @@ verifyFormat("var x = 'foo';", LeaveQuotes); } +TEST_F(FormatTestJS, SupportShebangLines) { + verifyFormat("#!/usr/bin/env node\n" + "var x = hello();", + "#!/usr/bin/env node\n" + "var x = hello();"); +} + } // end namespace tooling } // end namespace clang