diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index e81a543474f..7378c62a142 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -5959,7 +5959,7 @@ let TypeCheckOneImplFile rootSigOpt: ModuleOrNamespaceType option, synImplFile) = - let (ParsedImplFileInput (_, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland)) = synImplFile + let (ParsedImplFileInput (_, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _)) = synImplFile let infoReader = InfoReader(g, amap) cancellable { @@ -6080,7 +6080,7 @@ let TypeCheckOneImplFile /// Check an entire signature file -let TypeCheckOneSigFile (g, niceNameGen, amap, topCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring) tcEnv (ParsedSigFileInput (_, qualNameOfFile, _, _, sigFileFrags)) = +let TypeCheckOneSigFile (g, niceNameGen, amap, topCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring) tcEnv (ParsedSigFileInput (qualifiedNameOfFile = qualNameOfFile; modules = sigFileFrags)) = cancellable { let cenv = cenv.Create diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index b65bb99d614..d0513ed3b72 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -80,11 +80,11 @@ let PrependPathToSpec x (SynModuleOrNamespaceSig(p, b, c, d, e, f, g, h)) = let PrependPathToInput x inp = match inp with - | ParsedInput.ImplFile (ParsedImplFileInput (b, c, q, d, hd, impls, e)) -> - ParsedInput.ImplFile (ParsedImplFileInput (b, c, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToImpl x) impls, e)) + | ParsedInput.ImplFile (ParsedImplFileInput (b, c, q, d, hd, impls, e, trivia)) -> + ParsedInput.ImplFile (ParsedImplFileInput (b, c, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToImpl x) impls, e, trivia)) - | ParsedInput.SigFile (ParsedSigFileInput (b, q, d, hd, specs)) -> - ParsedInput.SigFile (ParsedSigFileInput (b, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToSpec x) specs)) + | ParsedInput.SigFile (ParsedSigFileInput (b, q, d, hd, specs, trivia)) -> + ParsedInput.SigFile (ParsedSigFileInput (b, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToSpec x) specs, trivia)) let ComputeAnonModuleName check defaultNamespace filename (m: range) = let modname = CanonicalizeFilename filename @@ -178,7 +178,7 @@ let GetScopedPragmasForHashDirective hd = | Some n -> yield ScopedPragma.WarningOff(m, n) | _ -> () ] -let PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, ParsedImplFile (hashDirectives, impls)) = +let PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, ParsedImplFile (hashDirectives, impls), lexbuf: UnicodeLexing.Lexbuf) = match impls |> List.rev |> List.tryPick (function ParsedImplFileFragment.NamedModule(SynModuleOrNamespace(lid, _, _, _, _, _, _, _)) -> Some lid | _ -> None) with | Some lid when impls.Length > 1 -> errorR(Error(FSComp.SR.buildMultipleToplevelModules(), rangeOfLid lid)) @@ -197,9 +197,11 @@ let PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, ParsedImp for hd in hashDirectives do yield! GetScopedPragmasForHashDirective hd ] - ParsedInput.ImplFile (ParsedImplFileInput (filename, isScript, qualName, scopedPragmas, hashDirectives, impls, isLastCompiland)) + let conditionalDirectives = LexbufIfdefStore.GetTrivia(lexbuf) + + ParsedInput.ImplFile (ParsedImplFileInput (filename, isScript, qualName, scopedPragmas, hashDirectives, impls, isLastCompiland, { ConditionalDirectives = conditionalDirectives })) -let PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, ParsedSigFile (hashDirectives, specs)) = +let PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, ParsedSigFile (hashDirectives, specs), lexbuf: UnicodeLexing.Lexbuf) = match specs |> List.rev |> List.tryPick (function ParsedSigFileFragment.NamedModule(SynModuleOrNamespaceSig(lid, _, _, _, _, _, _, _)) -> Some lid | _ -> None) with | Some lid when specs.Length > 1 -> errorR(Error(FSComp.SR.buildMultipleToplevelModules(), rangeOfLid lid)) @@ -217,7 +219,9 @@ let PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, ParsedSig for hd in hashDirectives do yield! GetScopedPragmasForHashDirective hd ] - ParsedInput.SigFile (ParsedSigFileInput (filename, qualName, scopedPragmas, hashDirectives, specs)) + let conditionalDirectives = LexbufIfdefStore.GetTrivia(lexbuf) + + ParsedInput.SigFile (ParsedSigFileInput (filename, qualName, scopedPragmas, hashDirectives, specs, { ConditionalDirectives = conditionalDirectives })) type ModuleNamesDict = Map> @@ -242,13 +246,13 @@ let DeduplicateModuleName (moduleNamesDict: ModuleNamesDict) fileName (qualNameO /// Checks if a ParsedInput is using a module name that was already given and deduplicates the name if needed. let DeduplicateParsedInputModuleName (moduleNamesDict: ModuleNamesDict) input = match input with - | ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, hashDirectives, modules, (isLastCompiland, isExe))) -> + | ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, hashDirectives, modules, (isLastCompiland, isExe), trivia)) -> let qualNameOfFileT, moduleNamesDictT = DeduplicateModuleName moduleNamesDict fileName qualNameOfFile - let inputT = ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (fileName, isScript, qualNameOfFileT, scopedPragmas, hashDirectives, modules, (isLastCompiland, isExe))) + let inputT = ParsedInput.ImplFile (ParsedImplFileInput.ParsedImplFileInput (fileName, isScript, qualNameOfFileT, scopedPragmas, hashDirectives, modules, (isLastCompiland, isExe), trivia)) inputT, moduleNamesDictT - | ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (fileName, qualNameOfFile, scopedPragmas, hashDirectives, modules)) -> + | ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (fileName, qualNameOfFile, scopedPragmas, hashDirectives, modules, trivia)) -> let qualNameOfFileT, moduleNamesDictT = DeduplicateModuleName moduleNamesDict fileName qualNameOfFile - let inputT = ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (fileName, qualNameOfFileT, scopedPragmas, hashDirectives, modules)) + let inputT = ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (fileName, qualNameOfFileT, scopedPragmas, hashDirectives, modules, trivia)) inputT, moduleNamesDictT let ParseInput (lexer, diagnosticOptions:FSharpDiagnosticOptions, errorLogger: ErrorLogger, lexbuf: UnicodeLexing.Lexbuf, defaultNamespace, filename, isLastCompiland) = @@ -279,11 +283,11 @@ let ParseInput (lexer, diagnosticOptions:FSharpDiagnosticOptions, errorLogger: E if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then let impl = Parser.implementationFile lexer lexbuf LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf) - PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, impl) + PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, impl, lexbuf) elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then let intfs = Parser.signatureFile lexer lexbuf LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf) - PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, intfs) + PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, intfs, lexbuf) else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then error(Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated filename, rangeStartup)) @@ -329,7 +333,7 @@ let ReportParsingStatistics res = let flattenModSpec (SynModuleOrNamespaceSig(_, _, _, decls, _, _, _, _)) = flattenSpecs decls let flattenModImpl (SynModuleOrNamespace(_, _, _, decls, _, _, _, _)) = flattenDefns decls match res with - | ParsedInput.SigFile (ParsedSigFileInput (_, _, _, _, specs)) -> + | ParsedInput.SigFile (ParsedSigFileInput (modules = specs)) -> printfn "parsing yielded %d specs" (List.collect flattenModSpec specs).Length | ParsedInput.ImplFile (ParsedImplFileInput (modules = impls)) -> printfn "parsing yielded %d definitions" (List.collect flattenModImpl impls).Length @@ -343,7 +347,8 @@ let EmptyParsedInput(filename, isLastCompiland) = QualFileNameOfImpls filename [], [], [], - [] + [], + { ConditionalDirectives = [] } ) ) else @@ -355,7 +360,8 @@ let EmptyParsedInput(filename, isLastCompiland) = [], [], [], - isLastCompiland + isLastCompiland, + { ConditionalDirectives = [] } ) ) @@ -645,11 +651,11 @@ let ProcessMetaCommandsFromInput decls match inp with - | ParsedInput.SigFile (ParsedSigFileInput (_, _, _, hashDirectives, specs)) -> + | ParsedInput.SigFile (ParsedSigFileInput (hashDirectives = hashDirectives; modules = specs)) -> let state = List.fold ProcessMetaCommand state0 hashDirectives let state = List.fold ProcessMetaCommandsFromModuleSpec state specs state - | ParsedInput.ImplFile (ParsedImplFileInput (_, _, _, _, hashDirectives, impls, _)) -> + | ParsedInput.ImplFile (ParsedImplFileInput (hashDirectives = hashDirectives; modules = impls)) -> let state = List.fold ProcessMetaCommand state0 hashDirectives let state = List.fold ProcessMetaCommandsFromModuleImpl state impls state @@ -832,7 +838,7 @@ let TypeCheckOneInput(checkForErrors, let m = inp.Range let amap = tcImports.GetImportMap() match inp with - | ParsedInput.SigFile (ParsedSigFileInput (_, qualNameOfFile, _, _, _) as file) -> + | ParsedInput.SigFile (ParsedSigFileInput (qualifiedNameOfFile = qualNameOfFile) as file) -> // Check if we've seen this top module signature before. if Zmap.mem qualNameOfFile tcState.tcsRootSigs then @@ -871,7 +877,7 @@ let TypeCheckOneInput(checkForErrors, return (tcEnv, EmptyTopAttrs, None, ccuSigForFile), tcState - | ParsedInput.ImplFile (ParsedImplFileInput (_, _, qualNameOfFile, _, _, _, _) as file) -> + | ParsedInput.ImplFile (ParsedImplFileInput (qualifiedNameOfFile = qualNameOfFile) as file) -> // Check if we've got an interface for this fragment let rootSigOpt = tcState.tcsRootSigs.TryFind qualNameOfFile diff --git a/src/fsharp/ParseHelpers.fs b/src/fsharp/ParseHelpers.fs index d784e4d73ac..494b2635bfe 100644 --- a/src/fsharp/ParseHelpers.fs +++ b/src/fsharp/ParseHelpers.fs @@ -6,6 +6,7 @@ open FSharp.Compiler.AbstractIL open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Features open FSharp.Compiler.Syntax +open FSharp.Compiler.SyntaxTrivia open FSharp.Compiler.SyntaxTreeOps open FSharp.Compiler.UnicodeLexing open FSharp.Compiler.Text @@ -87,7 +88,6 @@ type IParseState with //------------------------------------------------------------------------ /// XmlDoc F# lexer/parser state, held in the BufferLocalStore for the lexer. -/// This is the only use of the lexer BufferLocalStore in the codebase. module LexbufLocalXmlDocStore = // The key into the BufferLocalStore used to hold the current accumulated XmlDoc lines let private xmlDocKey = "XmlDoc" @@ -177,6 +177,56 @@ let rec LexerIfdefEval (lookup: string -> bool) = function | IfdefNot e -> not (LexerIfdefEval lookup e) | IfdefId id -> lookup id +/// Ifdef F# lexer/parser state, held in the BufferLocalStore for the lexer. +/// Used to capture #if, #else and #endif as syntax trivia. +module LexbufIfdefStore = + // The key into the BufferLocalStore used to hold the compiler directives + let private ifDefKey = "Ifdef" + + let private getStore (lexbuf: Lexbuf): ResizeArray = + match lexbuf.BufferLocalStore.TryGetValue ifDefKey with + | true, store -> store + | _ -> + let store = box (ResizeArray()) + lexbuf.BufferLocalStore.[ifDefKey] <- store + store + |> unbox> + + let private mkRangeWithoutLeadingWhitespace (lexed:string) (m:range): range = + let startColumn = lexed.Length - lexed.TrimStart().Length + mkFileIndexRange m.FileIndex (mkPos m.StartLine startColumn) m.End + + let SaveIfHash (lexbuf: Lexbuf, lexed:string, expr: LexerIfdefExpression, range: range) = + let store = getStore lexbuf + + let expr = + let rec visit (expr: LexerIfdefExpression) : IfDirectiveExpression = + match expr with + | LexerIfdefExpression.IfdefAnd(l,r) -> IfDirectiveExpression.And(visit l, visit r) + | LexerIfdefExpression.IfdefOr(l, r) -> IfDirectiveExpression.Or(visit l, visit r) + | LexerIfdefExpression.IfdefNot e -> IfDirectiveExpression.Not(visit e) + | LexerIfdefExpression.IfdefId id -> IfDirectiveExpression.Ident id + + visit expr + + let m = mkRangeWithoutLeadingWhitespace lexed range + + store.Add(ConditionalDirectiveTrivia.If(expr, m)) + + let SaveElseHash (lexbuf: Lexbuf, lexed:string, range: range) = + let store = getStore lexbuf + let m = mkRangeWithoutLeadingWhitespace lexed range + store.Add(ConditionalDirectiveTrivia.Else(m)) + + let SaveEndIfHash (lexbuf: Lexbuf, lexed:string, range: range) = + let store = getStore lexbuf + let m = mkRangeWithoutLeadingWhitespace lexed range + store.Add(ConditionalDirectiveTrivia.EndIf(m)) + + let GetTrivia (lexbuf: Lexbuf): ConditionalDirectiveTrivia list = + let store = getStore lexbuf + Seq.toList store + //------------------------------------------------------------------------ // Parsing: continuations for whitespace tokens //------------------------------------------------------------------------ diff --git a/src/fsharp/ParseHelpers.fsi b/src/fsharp/ParseHelpers.fsi index b97158e4b6f..69c30215365 100644 --- a/src/fsharp/ParseHelpers.fsi +++ b/src/fsharp/ParseHelpers.fsi @@ -74,6 +74,16 @@ type LexerIfdefExpression = val LexerIfdefEval: lookup:(string -> bool) -> _arg1:LexerIfdefExpression -> bool +module LexbufIfdefStore = + + val SaveIfHash: lexbuf:UnicodeLexing.Lexbuf * lexed:string * expr: LexerIfdefExpression * range: range -> unit + + val SaveElseHash: lexbuf:UnicodeLexing.Lexbuf * lexed:string * range: range -> unit + + val SaveEndIfHash: lexbuf:UnicodeLexing.Lexbuf * lexed:string * range: range -> unit + + val GetTrivia: lexbuf:UnicodeLexing.Lexbuf -> SyntaxTrivia.ConditionalDirectiveTrivia list + [] type LexerStringStyle = | Verbatim diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index a258b369b87..23b299abf2c 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -355,13 +355,13 @@ module ScriptPreprocessClosure = match List.frontAndBack closureFiles with | rest, ClosureFile (filename, m, - Some(ParsedInput.ImplFile (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, _))), + Some(ParsedInput.ImplFile (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, _, trivia))), parseDiagnostics, metaDiagnostics, nowarns) -> let isLastCompiland = (true, tcConfig.target.IsExe) rest @ [ClosureFile (filename, m, - Some(ParsedInput.ImplFile (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, isLastCompiland))), + Some(ParsedInput.ImplFile (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, isLastCompiland, trivia))), parseDiagnostics, metaDiagnostics, nowarns)] | _ -> closureFiles diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 5f19f5a300f..7665e7c3a26 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -2014,7 +2014,8 @@ type ParsedImplFileInput = scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * modules: SynModuleOrNamespace list * - isLastCompiland: (bool * bool) + isLastCompiland: (bool * bool) * + trivia: ParsedImplFileInputTrivia [] type ParsedSigFileInput = @@ -2023,7 +2024,8 @@ type ParsedSigFileInput = qualifiedNameOfFile: QualifiedNameOfFile * scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * - modules: SynModuleOrNamespaceSig list + modules: SynModuleOrNamespaceSig list * + trivia: ParsedSigFileInputTrivia [] type ParsedInput = diff --git a/src/fsharp/SyntaxTree.fsi b/src/fsharp/SyntaxTree.fsi index cbd1cd7f790..cf5d6e02594 100644 --- a/src/fsharp/SyntaxTree.fsi +++ b/src/fsharp/SyntaxTree.fsi @@ -2207,7 +2207,8 @@ type ParsedImplFileInput = scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * modules: SynModuleOrNamespace list * - isLastCompiland: (bool * bool) + isLastCompiland: (bool * bool) * + trivia: ParsedImplFileInputTrivia /// Represents the full syntax tree, file name and other parsing information for a signature file [] @@ -2217,7 +2218,8 @@ type ParsedSigFileInput = qualifiedNameOfFile: QualifiedNameOfFile * scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * - modules: SynModuleOrNamespaceSig list + modules: SynModuleOrNamespaceSig list * + trivia: ParsedSigFileInputTrivia /// Represents the syntax tree for a parsed implementation or signature file [] diff --git a/src/fsharp/SyntaxTrivia.fs b/src/fsharp/SyntaxTrivia.fs index be99b40a662..04031b83940 100644 --- a/src/fsharp/SyntaxTrivia.fs +++ b/src/fsharp/SyntaxTrivia.fs @@ -4,6 +4,26 @@ namespace FSharp.Compiler.SyntaxTrivia open FSharp.Compiler.Text +[] +type ConditionalDirectiveTrivia = + | If of expr:IfDirectiveExpression * range:range + | Else of range:range + | EndIf of range:range + +and [] IfDirectiveExpression = + | And of IfDirectiveExpression * IfDirectiveExpression + | Or of IfDirectiveExpression * IfDirectiveExpression + | Not of IfDirectiveExpression + | Ident of string + +[] +type ParsedImplFileInputTrivia = + { ConditionalDirectives: ConditionalDirectiveTrivia list } + +[] +type ParsedSigFileInputTrivia = + { ConditionalDirectives: ConditionalDirectiveTrivia list } + [] type SynExprTryWithTrivia = { TryKeyword: range diff --git a/src/fsharp/SyntaxTrivia.fsi b/src/fsharp/SyntaxTrivia.fsi index eab574e1bb2..fbf84c8f560 100644 --- a/src/fsharp/SyntaxTrivia.fsi +++ b/src/fsharp/SyntaxTrivia.fsi @@ -1,9 +1,37 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace FSharp.Compiler.SyntaxTrivia +namespace rec FSharp.Compiler.SyntaxTrivia open FSharp.Compiler.Text +[] +type ConditionalDirectiveTrivia = + | If of expr:IfDirectiveExpression * range:range + | Else of range:range + | EndIf of range:range + +type [] IfDirectiveExpression = + | And of IfDirectiveExpression * IfDirectiveExpression + | Or of IfDirectiveExpression * IfDirectiveExpression + | Not of IfDirectiveExpression + | Ident of string + +/// Represents additional information for ParsedImplFileInput +[] +type ParsedImplFileInputTrivia = + { + /// Preprocessor directives of type #if, #else or #endif + ConditionalDirectives: ConditionalDirectiveTrivia list + } + +/// Represents additional information for ParsedSigFileInputTrivia +[] +type ParsedSigFileInputTrivia = + { + /// Preprocessor directives of type #if, #else or #endif + ConditionalDirectives: ConditionalDirectiveTrivia list + } + /// Represents additional information for SynExpr.TryWith [] type SynExprTryWithTrivia = @@ -178,4 +206,4 @@ type SynModuleSigDeclNestedModuleTrivia = /// The syntax range of the `=` token. EqualsRange: range option } - static member Zero: SynModuleSigDeclNestedModuleTrivia \ No newline at end of file + static member Zero: SynModuleSigDeclNestedModuleTrivia diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index a13d8083e30..34b76ca4aa1 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1778,7 +1778,7 @@ type internal FsiDynamicCompiler let impl = SynModuleOrNamespace(prefix,(*isRec*)false, SynModuleOrNamespaceKind.NamedModule,defs,PreXmlDoc.Empty,[],None,m) let isLastCompiland = true let isExe = false - let input = ParsedInput.ImplFile (ParsedImplFileInput (filename,true, ComputeQualifiedNameOfFileFromUniquePath (m,prefixPath),[],[],[impl],(isLastCompiland, isExe) )) + let input = ParsedInput.ImplFile (ParsedImplFileInput (filename,true, ComputeQualifiedNameOfFileFromUniquePath (m,prefixPath),[],[],[impl],(isLastCompiland, isExe), { ConditionalDirectives = [] })) let isIncrementalFragment = true let istate,tcEnvAtEndOfLastInput,declaredImpls = ProcessInputs (ctok, errorLogger, istate, [input], showTypes, isIncrementalFragment, isInteractiveItExpr, prefix, m) let tcState = istate.tcState diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index e98d6a03417..ee51a268cc1 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -216,7 +216,7 @@ let evalIfDefExpression startPos reportLibraryOnlyFeatures langVersion args (loo lexbuf.EndPos <- startPos let tokenStream = FSharp.Compiler.PPLexer.tokenstream args let expr = FSharp.Compiler.PPParser.start tokenStream lexbuf - LexerIfdefEval lookup expr + (LexerIfdefEval lookup expr), expr let evalFloat args lexbuf = try @@ -943,8 +943,9 @@ rule token args skip = parse { let m = lexbuf.LexemeRange let lookup id = List.contains id args.defines let lexed = lexeme lexbuf - let isTrue = evalIfDefExpression lexbuf.StartPos lexbuf.ReportLibraryOnlyFeatures lexbuf.LanguageVersion args lookup lexed + let isTrue, expr = evalIfDefExpression lexbuf.StartPos lexbuf.ReportLibraryOnlyFeatures lexbuf.LanguageVersion args lookup lexed args.ifdefStack <- (IfDefIf,m) :: args.ifdefStack + LexbufIfdefStore.SaveIfHash(lexbuf, lexed, expr, m) // Get the token; make sure it starts at zero position & return let cont, f = @@ -968,6 +969,7 @@ rule token args skip = parse | (IfDefIf,_) :: rest -> let m = lexbuf.LexemeRange args.ifdefStack <- (IfDefElse,m) :: rest + LexbufIfdefStore.SaveElseHash(lexbuf, lexed, m) let tok = HASH_ELSE(m, lexed, LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(0, m))) let tok = shouldStartLine args lexbuf m (FSComp.SR.lexHashElseMustBeFirst()) tok if not skip then tok else endline (LexerEndlineContinuation.Skip(0, m)) args skip lexbuf } @@ -979,6 +981,7 @@ rule token args skip = parse | []-> LEX_FAILURE (FSComp.SR.lexHashEndingNoMatchingIf()) | _ :: rest -> args.ifdefStack <- rest + LexbufIfdefStore.SaveEndIfHash(lexbuf, lexed, m) let tok = HASH_ENDIF(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) let tok = shouldStartLine args lexbuf m (FSComp.SR.lexHashEndifMustBeFirst()) tok if not skip then tok else endline LexerEndlineContinuation.Token args skip lexbuf } @@ -1015,6 +1018,10 @@ and ifdefSkip n m args skip = parse if not skip then INACTIVECODE (LexCont.IfDefSkip(args.ifdefStack, args.stringNest, n, m)) else ifdefSkip n m args skip lexbuf else + let lexed = lexeme lexbuf + let lookup id = List.contains id args.defines + let _, expr = evalIfDefExpression lexbuf.StartPos lexbuf.ReportLibraryOnlyFeatures lexbuf.LanguageVersion args lookup lexed + LexbufIfdefStore.SaveIfHash(lexbuf, lexed, expr, m) let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n+1, m))) if not skip then tok else endline (LexerEndlineContinuation.Skip(n+1, m)) args skip lexbuf } @@ -1032,10 +1039,12 @@ and ifdefSkip n m args skip = parse | (IfDefElse,_) :: _rest -> LEX_FAILURE (FSComp.SR.lexHashEndifRequiredForElse()) | (IfDefIf,_) :: rest -> let m = lexbuf.LexemeRange + LexbufIfdefStore.SaveElseHash(lexbuf, lexed, m) args.ifdefStack <- (IfDefElse,m) :: rest if not skip then HASH_ELSE(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) else endline LexerEndlineContinuation.Token args skip lexbuf else + LexbufIfdefStore.SaveElseHash(lexbuf, lexed, m) if not skip then INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n, m))) else endline (LexerEndlineContinuation.Skip(n, m)) args skip lexbuf } @@ -1051,10 +1060,12 @@ and ifdefSkip n m args skip = parse match args.ifdefStack with | [] -> LEX_FAILURE (FSComp.SR.lexHashEndingNoMatchingIf()) | _ :: rest -> + LexbufIfdefStore.SaveEndIfHash(lexbuf, lexed, m) args.ifdefStack <- rest if not skip then HASH_ENDIF(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) else endline LexerEndlineContinuation.Token args skip lexbuf else + LexbufIfdefStore.SaveEndIfHash(lexbuf, lexed, m) let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n-1, m))) let tok = shouldStartLine args lexbuf m (FSComp.SR.lexWrongNestedHashEndif()) tok if not skip then tok else endline (LexerEndlineContinuation.Skip(n-1, m)) args skip lexbuf } diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index f10aa68bf8a..f8c5581dad8 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -120,7 +120,8 @@ module IncrementalBuildSyntaxTree = [], [], [], - isLastCompiland + isLastCompiland, + { ConditionalDirectives = [] } ) ) else diff --git a/src/fsharp/service/ServiceNavigation.fs b/src/fsharp/service/ServiceNavigation.fs index 1446b607ad8..a0935471e1f 100755 --- a/src/fsharp/service/ServiceNavigation.fs +++ b/src/fsharp/service/ServiceNavigation.fs @@ -589,7 +589,7 @@ module NavigateTo = let ctor = mapMemberKind memberFlags.MemberKind addValSig ctor valSig isSig container - let rec walkSigFileInput (ParsedSigFileInput (fileName, _, _, _, moduleOrNamespaceList)) = + let rec walkSigFileInput (ParsedSigFileInput (fileName = fileName; modules = moduleOrNamespaceList)) = for item in moduleOrNamespaceList do walkSynModuleOrNamespaceSig item { Type = NavigableContainerType.File; Name = fileName } diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs index e0486c120a0..8d7369e62b2 100755 --- a/src/fsharp/service/ServiceParseTreeWalk.fs +++ b/src/fsharp/service/ServiceParseTreeWalk.fs @@ -808,7 +808,7 @@ module SyntaxTraversal = visitor.VisitBinding(origPath, defaultTraverse,b) match parseTree with - | ParsedInput.ImplFile (ParsedImplFileInput (_,_,_,_,_,l,_))-> + | ParsedInput.ImplFile (ParsedImplFileInput (modules = l))-> let fileRange = #if DEBUG match l with [] -> range0 | _ -> l |> List.map (fun x -> x.Range) |> List.reduce unionRanges diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 6384964188c..7b2c727a8a7 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -5505,9 +5505,11 @@ FSharp.Compiler.Syntax.ParsedImplFileFragment: System.String ToString() FSharp.Compiler.Syntax.ParsedImplFileInput FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean get_isScript() FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean isScript -FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.ParsedImplFileInput NewParsedImplFileInput(System.String, Boolean, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace], System.Tuple`2[System.Boolean,System.Boolean]) +FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.ParsedImplFileInput NewParsedImplFileInput(System.String, Boolean, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace], System.Tuple`2[System.Boolean,System.Boolean], FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia) FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_qualifiedNameOfFile() FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile qualifiedNameOfFile +FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia get_trivia() +FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia trivia FSharp.Compiler.Syntax.ParsedImplFileInput: Int32 Tag FSharp.Compiler.Syntax.ParsedImplFileInput: Int32 get_Tag() FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective] get_hashDirectives() @@ -5617,9 +5619,11 @@ FSharp.Compiler.Syntax.ParsedSigFileFragment: Int32 Tag FSharp.Compiler.Syntax.ParsedSigFileFragment: Int32 get_Tag() FSharp.Compiler.Syntax.ParsedSigFileFragment: System.String ToString() FSharp.Compiler.Syntax.ParsedSigFileInput -FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.ParsedSigFileInput NewParsedSigFileInput(System.String, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig]) +FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.ParsedSigFileInput NewParsedSigFileInput(System.String, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig], FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia) FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_qualifiedNameOfFile() FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile qualifiedNameOfFile +FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia get_trivia() +FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia trivia FSharp.Compiler.Syntax.ParsedSigFileInput: Int32 Tag FSharp.Compiler.Syntax.ParsedSigFileInput: Int32 get_Tag() FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective] get_hashDirectives() @@ -9085,6 +9089,81 @@ FSharp.Compiler.Syntax.TyparStaticReq: Int32 GetHashCode(System.Collections.IEqu FSharp.Compiler.Syntax.TyparStaticReq: Int32 Tag FSharp.Compiler.Syntax.TyparStaticReq: Int32 get_Tag() FSharp.Compiler.Syntax.TyparStaticReq: System.String ToString() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Else: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Else: FSharp.Compiler.Text.Range range +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+EndIf: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+EndIf: FSharp.Compiler.Text.Range range +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+If: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression expr +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+If: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_expr() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+If: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+If: FSharp.Compiler.Text.Range range +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Tags: Int32 Else +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Tags: Int32 EndIf +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Tags: Int32 If +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean IsElse +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean IsEndIf +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean IsIf +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean get_IsElse() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean get_IsEndIf() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Boolean get_IsIf() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia NewElse(FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia NewEndIf(FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia NewIf(FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Else +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+EndIf +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+If +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia+Tags +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Int32 Tag +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: Int32 get_Tag() +FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+And: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression Item1 +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+And: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression Item2 +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+And: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_Item1() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+And: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_Item2() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Ident: System.String Item +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Ident: System.String get_Item() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Not: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression Item +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Not: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_Item() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Or: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression Item1 +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Or: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression Item2 +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Or: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_Item1() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Or: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression get_Item2() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Tags: Int32 And +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Tags: Int32 Ident +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Tags: Int32 Not +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Tags: Int32 Or +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean IsAnd +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean IsIdent +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean IsNot +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean IsOr +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean get_IsAnd() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean get_IsIdent() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean get_IsNot() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Boolean get_IsOr() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression NewAnd(FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression, FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression) +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression NewIdent(System.String) +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression NewNot(FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression) +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression NewOr(FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression, FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression) +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+And +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Ident +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Not +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Or +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression+Tags +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Int32 Tag +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: Int32 get_Tag() +FSharp.Compiler.SyntaxTrivia.IfDirectiveExpression: System.String ToString() +FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia +FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia] ConditionalDirectives +FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia] get_ConditionalDirectives() +FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia: Void .ctor(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia]) +FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia +FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia] ConditionalDirectives +FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia] get_ConditionalDirectives() +FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Void .ctor(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia]) FSharp.Compiler.SyntaxTrivia.SynBindingTrivia FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia Zero FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia get_Zero() diff --git a/tests/service/InteractiveCheckerTests.fs b/tests/service/InteractiveCheckerTests.fs index 12d80181986..b784b487bad 100644 --- a/tests/service/InteractiveCheckerTests.fs +++ b/tests/service/InteractiveCheckerTests.fs @@ -54,7 +54,7 @@ let internal identsAndRanges (input: ParsedInput) = (identAndRange (longIdentToString longIdent) (longIdent |> List.map (fun id -> id.idRange) |> List.reduce unionRanges)) :: xs match input with - | ParsedInput.ImplFile(ParsedImplFileInput(_, _, _, _, _, modulesOrNamespaces, _)) -> + | ParsedInput.ImplFile(ParsedImplFileInput(modules = modulesOrNamespaces)) -> modulesOrNamespaces |> List.collect extractFromModuleOrNamespace | ParsedInput.SigFile _ -> [] diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 20ba3ca4612..ce9c9c8e478 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -11,6 +11,7 @@ open System open FSharp.Compiler.Service.Tests.Common open FSharp.Compiler.Symbols open FSharp.Compiler.Syntax +open FSharp.Compiler.SyntaxTrivia open FsUnit open NUnit.Framework @@ -3301,3 +3302,355 @@ async { assertRange (5, 4) (5, 24) mAndBang2 | _ -> Assert.Fail "Could not get valid AST" + +module ConditionalDirectives = + let private getDirectiveTrivia isSignatureFile source = + let ast = (if isSignatureFile then getParseResultsOfSignatureFile else getParseResults) source + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(trivia = { ConditionalDirectives = trivia })) + | ParsedInput.SigFile(ParsedSigFileInput(trivia = { ConditionalDirectives = trivia })) -> trivia + + [] + let ``single #if / #endif`` () = + let trivia = + getDirectiveTrivia false """ +let v = + #if DEBUG + () + #endif + 42 +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr, mIf) + ConditionalDirectiveTrivia.EndIf mEndif ] -> + assertRange (3, 4) (3, 13) mIf + assertRange (5, 4) (5, 10) mEndif + + match expr with + | IfDirectiveExpression.Ident "DEBUG" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``single #if / #else / #endif`` () = + let trivia = + getDirectiveTrivia false """ +let v = + #if DEBUG + 30 + #else + 42 + #endif +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr, mIf) + ConditionalDirectiveTrivia.Else mElse + ConditionalDirectiveTrivia.EndIf mEndif ] -> + assertRange (3, 4) (3, 13) mIf + assertRange (5, 4) (5, 9) mElse + assertRange (7, 4) (7, 10) mEndif + + match expr with + | IfDirectiveExpression.Ident "DEBUG" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``nested #if / #else / #endif`` () = + let trivia = + getDirectiveTrivia false """ +let v = + #if FOO + #if MEH + 1 + #else + 2 + #endif + #else + 3 + #endif +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr1, mIf1) + ConditionalDirectiveTrivia.If(expr2, mIf2) + ConditionalDirectiveTrivia.Else mElse1 + ConditionalDirectiveTrivia.EndIf mEndif1 + ConditionalDirectiveTrivia.Else mElse2 + ConditionalDirectiveTrivia.EndIf mEndif2 ] -> + assertRange (3, 4) (3, 11) mIf1 + assertRange (4, 8) (4, 15) mIf2 + assertRange (6, 8) (6, 13) mElse1 + assertRange (8, 8) (8, 14) mEndif1 + assertRange (9, 4) (9, 9) mElse2 + assertRange (11, 4) (11, 10) mEndif2 + + match expr1 with + | IfDirectiveExpression.Ident "FOO" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr1}" + + match expr2 with + | IfDirectiveExpression.Ident "MEH" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr2}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``nested #if / #endif with complex expressions`` () = + let trivia = + getDirectiveTrivia false """ +let v = + #if !DEBUG + #if FOO && BAR + #if MEH || HMM + printfn "oh some logging" + #endif + #endif + #endif +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr1, mIf1) + ConditionalDirectiveTrivia.If(expr2, mIf2) + ConditionalDirectiveTrivia.If(expr3, mIf3) + ConditionalDirectiveTrivia.EndIf mEndif1 + ConditionalDirectiveTrivia.EndIf mEndif2 + ConditionalDirectiveTrivia.EndIf mEndif3 ] -> + assertRange (3, 4) (3, 14) mIf1 + assertRange (4, 8) (4, 22) mIf2 + assertRange (5, 12) (5, 26) mIf3 + assertRange (7, 12) (7, 18) mEndif1 + assertRange (8, 8) (8, 14) mEndif2 + assertRange (9, 4) (9, 10) mEndif3 + + match expr1 with + | IfDirectiveExpression.Not (IfDirectiveExpression.Ident "DEBUG") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr1}" + + match expr2 with + | IfDirectiveExpression.And(IfDirectiveExpression.Ident "FOO", IfDirectiveExpression.Ident "BAR") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr2}" + + match expr3 with + | IfDirectiveExpression.Or(IfDirectiveExpression.Ident "MEH", IfDirectiveExpression.Ident "HMM") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr3}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``directives in multiline comment are not reported as trivia`` () = + let trivia = + getDirectiveTrivia false """ +let v = +(* + #if DEBUG + () + #endif +*) + 42 +""" + + match trivia with + | [] -> Assert.Pass() + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``directives in multiline string are not reported as trivia`` () = + let trivia = + getDirectiveTrivia false " +let v = \"\"\" + #if DEBUG + () + #endif + 42 +\"\"\" +" + + match trivia with + | [] -> Assert.Pass() + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``single #if / #endif, signature file`` () = + let trivia = + getDirectiveTrivia true """ +namespace Foobar + +val v: int = + #if DEBUG + 1 + #endif + 42 +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr, mIf) + ConditionalDirectiveTrivia.EndIf mEndif ] -> + assertRange (5, 4) (5, 13) mIf + assertRange (7, 4) (7, 10) mEndif + + match expr with + | IfDirectiveExpression.Ident "DEBUG" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``single #if / #else / #endif, signature file`` () = + let trivia = + getDirectiveTrivia true """ +namespace Foobar + +val v : int = + #if DEBUG + 30 + #else + 42 + #endif +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr, mIf) + ConditionalDirectiveTrivia.Else mElse + ConditionalDirectiveTrivia.EndIf mEndif ] -> + assertRange (5, 4) (5, 13) mIf + assertRange (7, 4) (7, 9) mElse + assertRange (9, 4) (9, 10) mEndif + + match expr with + | IfDirectiveExpression.Ident "DEBUG" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``nested #if / #else / #endif, signature file`` () = + let trivia = + getDirectiveTrivia true """ +namespace Foobar + +val v : int = + #if FOO + #if MEH + 1 + #else + 2 + #endif + #else + 3 + #endif +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr1, mIf1) + ConditionalDirectiveTrivia.If(expr2, mIf2) + ConditionalDirectiveTrivia.Else mElse1 + ConditionalDirectiveTrivia.EndIf mEndif1 + ConditionalDirectiveTrivia.Else mElse2 + ConditionalDirectiveTrivia.EndIf mEndif2 ] -> + assertRange (5, 4) (5, 11) mIf1 + assertRange (6, 8) (6, 15) mIf2 + assertRange (8, 8) (8, 13) mElse1 + assertRange (10, 8) (10, 14) mEndif1 + assertRange (11, 4) (11, 9) mElse2 + assertRange (13, 4) (13, 10) mEndif2 + + match expr1 with + | IfDirectiveExpression.Ident "FOO" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr1}" + + match expr2 with + | IfDirectiveExpression.Ident "MEH" -> () + | _ -> Assert.Fail $"Expected different expression, got {expr2}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``nested #if / #endif with complex expressions, signature file`` () = + let trivia = + getDirectiveTrivia true """ +namespace Foobar + +val v : int = + #if !DEBUG + #if FOO && BAR + #if MEH || HMM + 9 + #endif + #endif + #endif + 10 +""" + + match trivia with + | [ ConditionalDirectiveTrivia.If(expr1, mIf1) + ConditionalDirectiveTrivia.If(expr2, mIf2) + ConditionalDirectiveTrivia.If(expr3, mIf3) + ConditionalDirectiveTrivia.EndIf mEndif1 + ConditionalDirectiveTrivia.EndIf mEndif2 + ConditionalDirectiveTrivia.EndIf mEndif3 ] -> + assertRange (5, 4) (5, 14) mIf1 + assertRange (6, 8) (6, 22) mIf2 + assertRange (7, 12) (7, 26) mIf3 + assertRange (9, 12) (9, 18) mEndif1 + assertRange (10, 8) (10, 14) mEndif2 + assertRange (11, 4) (11, 10) mEndif3 + + match expr1 with + | IfDirectiveExpression.Not (IfDirectiveExpression.Ident "DEBUG") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr1}" + + match expr2 with + | IfDirectiveExpression.And(IfDirectiveExpression.Ident "FOO", IfDirectiveExpression.Ident "BAR") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr2}" + + match expr3 with + | IfDirectiveExpression.Or(IfDirectiveExpression.Ident "MEH", IfDirectiveExpression.Ident "HMM") -> () + | _ -> Assert.Fail $"Expected different expression, got {expr3}" + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``directives in multiline comment are not reported as trivia, signature file`` () = + let trivia = + getDirectiveTrivia true """ +namespace Foobar + +val v : int = +(* + #if DEBUG + () + #endif +*) + 42 +""" + + match trivia with + | [] -> Assert.Pass() + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}" + + [] + let ``directives in multiline string are not reported as trivia, signature file`` () = + let trivia = + getDirectiveTrivia true " +namespace Foobar + +let v : string = \"\"\" + #if DEBUG + () + #endif + 42 +\"\"\" +" + + match trivia with + | [] -> Assert.Pass() + | _ -> + Assert.Fail $"Unexpected trivia, got {trivia}"