diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index e3f5e3796db..e306856bfeb 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -43,7 +43,11 @@ let posOfLexPosition (p: Position) = mkPos p.Line p.Column /// Get an F# compiler range from a lexer range let mkSynRange (p1: Position) (p2: Position) = - mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) + if p1.FileIndex = p2.FileIndex then + mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) + else + // This means we had a #line directive in the middle of this syntax element. + mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition (p1.ShiftColumnBy 1)) type LexBuffer<'Char> with diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Line.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Line.fs new file mode 100644 index 00000000000..4844fb232b3 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Line.fs @@ -0,0 +1,66 @@ +namespace CompilerDirectives + +open Microsoft.FSharp.Control +open Xunit +open FSharp.Test.Compiler +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Text +open FSharp.Compiler.Syntax + +module Line = + + let checker = FSharpChecker.Create() + + let parse (source: string) = + let langVersion = "preview" + let sourceFileName = __SOURCE_FILE__ + let parsingOptions = + { FSharpParsingOptions.Default with + SourceFiles = [| sourceFileName |] + LangVersionText = langVersion + ApplyLineDirectives = true + } + checker.ParseFile(sourceFileName, SourceText.ofString source, parsingOptions) |> Async.RunSynchronously + + + [] + let private case1 = """module A +#line 1 "xyz.fs" +( +printfn "" +) + """ + + [] + let private case2 = """module A +( +#line 1 "xyz.fs" +printfn "" +) + """ + + [] + let private case3 = """module A +( +#line 1 "xyz.fs" +) + """ + + [] + [] + [] + [] + let ``check expr range interacting with line directive`` (case, source, expectedRange) = + let parseResults = parse source + if parseResults.ParseHadErrors then failwith "unexpected: parse error" + let exprRange = + match parseResults.ParseTree with + | ParsedInput.ImplFile(ParsedImplFileInput(contents = contents)) -> + let (SynModuleOrNamespace(decls = decls)) = List.exactlyOne contents + match List.exactlyOne decls with + | SynModuleDecl.Expr(_, range) -> $"{range.FileName}:{range}" + | _ -> failwith $"unexpected: not an expr" + | ParsedInput.SigFile _ -> failwith "unexpected: sig file" + if exprRange <> expectedRange then + failwith $"case{case}: expected: {expectedRange}, found {exprRange}" + \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/Directives.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs similarity index 99% rename from tests/FSharp.Compiler.ComponentTests/ErrorMessages/Directives.fs rename to tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs index 14377fbe8b3..080811bd7c2 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/Directives.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace ErrorMessages +namespace CompilerDirectives open Xunit open FSharp.Test.Compiler -module HashDirectives = +module NonStringArgs = [] [] diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 007e3f23460..9d65f2bef9b 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -31,6 +31,8 @@ FsUnit.fs + + @@ -177,9 +179,9 @@ + - @@ -196,7 +198,6 @@ -