diff --git a/eng/config/BannedSymbols.txt b/eng/config/BannedSymbols.txt index 8558e121b5dc2..9c707886b0b18 100644 --- a/eng/config/BannedSymbols.txt +++ b/eng/config/BannedSymbols.txt @@ -47,14 +47,14 @@ M:Microsoft.CodeAnalysis.Editing.SyntaxEditor.#ctor(Microsoft.CodeAnalysis.Synta M:Microsoft.CodeAnalysis.FileTextLoader.#ctor(System.String,System.Text.Encoding); use WorkspaceFileTextLoader that calls on ITextFactoryService to create SourceText M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SyntaxTree(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding); Use CSharpSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use CSharpSyntaxTree sublass that takes checksum algorithm -M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode); Use CSharpSyntaxTree sublass that takes checksum algorithm +M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions); Use CSharpSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options, System.String path, System.Text.Encoding encoding); Use CSharpSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use API that takes SourceText M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Nullable{System.Boolean},System.Threading.CancellationToken); Use API that takes SourceText M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.SyntaxTree(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding); Use VisualBasicSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use overload with SourceText M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken); Use overload with SourceText -M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode); Use VisualBasicSyntaxTree sublass that takes checksum algorithm +M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions); Use VisualBasicSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.Create(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic}); Use VisualBasicSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.Create(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding); Use VisualBasicSyntaxTree sublass that takes checksum algorithm M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken); Use overload with SourceText diff --git a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxNode.cs b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxNode.cs index 3b09234ad0c18..3f27691d9e952 100644 --- a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxNode.cs +++ b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxNode.cs @@ -9,9 +9,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -73,8 +71,8 @@ private static SyntaxTree ComputeSyntaxTree(CSharpSyntaxNode node) if (parent == null) { // set the tree on the root node atomically -#pragma warning disable RS0030 // Do not use banned APIs (CreateWithoutClone is intended to be used from this call site only) - Interlocked.CompareExchange(ref node._syntaxTree, CSharpSyntaxTree.CreateWithoutClone(node), null); +#pragma warning disable RS0030 // Do not use banned APIs (CreateWithoutClone is intended to be used from this call site) + Interlocked.CompareExchange(ref node._syntaxTree, CSharpSyntaxTree.CreateWithoutClone(node, CSharpParseOptions.Default), null); #pragma warning restore tree = node._syntaxTree; break; diff --git a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs index 6cf328da50821..103c8509f5c28 100644 --- a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs +++ b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs @@ -8,8 +8,6 @@ using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -390,10 +388,10 @@ internal static SyntaxTree CreateForDebugger(CSharpSyntaxNode root, SourceText t /// Internal helper for class to create a new syntax tree rooted at the given root node. /// This method does not create a clone of the given root, but instead preserves it's reference identity. /// - /// NOTE: This method is only intended to be used from property. + /// NOTE: This method is only intended to be used from property and SyntaxFactory.Parse* methods. /// NOTE: Do not use this method elsewhere, instead use method for creating a syntax tree. /// - internal static SyntaxTree CreateWithoutClone(CSharpSyntaxNode root) + internal static SyntaxTree CreateWithoutClone(CSharpSyntaxNode root, CSharpParseOptions options) { Debug.Assert(root != null); @@ -402,7 +400,7 @@ internal static SyntaxTree CreateWithoutClone(CSharpSyntaxNode root) encodingOpt: null, checksumAlgorithm: SourceHashAlgorithm.Sha1, path: "", - options: CSharpParseOptions.Default, + options: options, root: root, directives: default, diagnosticOptions: null, diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index a1cbe33a1b30f..5b57505194954 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1694,7 +1694,7 @@ public static NameSyntax ParseName(string text, int offset = 0, bool consumeFull { var node = parser.ParseName(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (NameSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1718,7 +1718,7 @@ public static TypeSyntax ParseTypeName(string text, int offset = 0, ParseOptions { var node = parser.ParseTypeName(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (TypeSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1737,7 +1737,7 @@ public static ExpressionSyntax ParseExpression(string text, int offset = 0, Pars { var node = parser.ParseExpression(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (ExpressionSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1756,7 +1756,7 @@ public static StatementSyntax ParseStatement(string text, int offset = 0, ParseO { var node = parser.ParseStatement(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (StatementSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1780,7 +1780,7 @@ public static StatementSyntax ParseStatement(string text, int offset = 0, ParseO return null; } - return (MemberDeclarationSyntax)(consumeFullText ? parser.ConsumeUnexpectedTokens(node) : node).CreateRed(); + return CreateRed(consumeFullText ? parser.ConsumeUnexpectedTokens(node) : node, lexer.Options); } } @@ -1800,7 +1800,7 @@ public static CompilationUnitSyntax ParseCompilationUnit(string text, int offset using (var parser = MakeParser(lexer)) { var node = parser.ParseCompilationUnit(); - return (CompilationUnitSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1819,7 +1819,7 @@ public static ParameterListSyntax ParseParameterList(string text, int offset = 0 { var node = parser.ParseParenthesizedParameterList(forExtension: false); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (ParameterListSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1838,7 +1838,7 @@ public static BracketedParameterListSyntax ParseBracketedParameterList(string te { var node = parser.ParseBracketedParameterList(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (BracketedParameterListSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1857,7 +1857,7 @@ public static ArgumentListSyntax ParseArgumentList(string text, int offset = 0, { var node = parser.ParseParenthesizedArgumentList(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (ArgumentListSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1876,7 +1876,7 @@ public static BracketedArgumentListSyntax ParseBracketedArgumentList(string text { var node = parser.ParseBracketedArgumentList(); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (BracketedArgumentListSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); } } @@ -1902,7 +1902,18 @@ public static BracketedArgumentListSyntax ParseBracketedArgumentList(string text annotations: null); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (AttributeArgumentListSyntax)node.CreateRed(); + return CreateRed(node, lexer.Options); + } + + private static TSyntax CreateRed(InternalSyntax.CSharpSyntaxNode green, CSharpParseOptions options) + where TSyntax : CSharpSyntaxNode + { + var red = (TSyntax)green.CreateRed(); + Debug.Assert(red._syntaxTree is null); +#pragma warning disable RS0030 // Do not use banned APIs (CreateWithoutClone is intended to be used from this call site) + red._syntaxTree = CSharpSyntaxTree.CreateWithoutClone(red, options); +#pragma warning restore + return red; } /// diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SyntaxTreeRootTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SyntaxTreeRootTests.cs index a5bdfcbdb0f5a..43b0b048eb0f2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SyntaxTreeRootTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SyntaxTreeRootTests.cs @@ -4,17 +4,12 @@ #nullable disable -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Xunit; -using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.Semantics { @@ -32,7 +27,7 @@ public void SyntaxTreeCreateAcceptsAnySyntaxNode() public void SyntaxTreeCreateWithoutCloneAcceptsAnySyntaxNode() { var node = SyntaxFactory.CatchClause(SyntaxFactory.CatchDeclaration(SyntaxFactory.ParseTypeName(typeof(InvalidOperationException).Name)), null, SyntaxFactory.Block()); - var tree = CSharpSyntaxTree.CreateWithoutClone(node); + var tree = CSharpSyntaxTree.CreateWithoutClone(node, CSharpParseOptions.Default); CheckTree(tree); } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs index 49178bb9c5a9e..bc2e73ce0a952 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs @@ -9,11 +9,11 @@ using System.Linq; using System.Text; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; using InternalSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax; -using Microsoft.CodeAnalysis.CSharp.Test.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -678,5 +678,41 @@ public void TestParseNameWithOptions() // unsafe class C { delegate* x; } Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("C.x").WithLocation(1, 34)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78510")] + public void TestParseMethodsKeepParseOptionsInTheTree() + { + var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); + + var argList = SyntaxFactory.ParseArgumentList("", options: parseOptions); + Assert.Same(parseOptions, argList.SyntaxTree.Options); + + var attrArgList = SyntaxFactory.ParseAttributeArgumentList("", options: parseOptions); + Assert.Same(parseOptions, attrArgList.SyntaxTree.Options); + + var bracketedArgList = SyntaxFactory.ParseBracketedArgumentList("", options: parseOptions); + Assert.Same(parseOptions, bracketedArgList.SyntaxTree.Options); + + var bracketedParamList = SyntaxFactory.ParseBracketedParameterList("", options: parseOptions); + Assert.Same(parseOptions, bracketedParamList.SyntaxTree.Options); + + var compUnit = SyntaxFactory.ParseCompilationUnit("", options: parseOptions); + Assert.Same(parseOptions, compUnit.SyntaxTree.Options); + + var expr = SyntaxFactory.ParseExpression("", options: parseOptions); + Assert.Same(parseOptions, expr.SyntaxTree.Options); + + var memberDecl = SyntaxFactory.ParseMemberDeclaration("public", options: parseOptions); + Assert.Same(parseOptions, memberDecl.SyntaxTree.Options); + + var paramList = SyntaxFactory.ParseParameterList("", options: parseOptions); + Assert.Same(parseOptions, paramList.SyntaxTree.Options); + + var statement = SyntaxFactory.ParseStatement("", options: parseOptions); + Assert.Same(parseOptions, statement.SyntaxTree.Options); + + var typeName = SyntaxFactory.ParseTypeName("", options: parseOptions); + Assert.Same(parseOptions, typeName.SyntaxTree.Options); + } } } diff --git a/src/Compilers/VisualBasic/Portable/Parser/Parser.vb b/src/Compilers/VisualBasic/Portable/Parser/Parser.vb index 2b7dc24d71d1f..7a2a53a2413a0 100644 --- a/src/Compilers/VisualBasic/Portable/Parser/Parser.vb +++ b/src/Compilers/VisualBasic/Portable/Parser/Parser.vb @@ -70,6 +70,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax End If End Sub + Friend ReadOnly Property Options As VisualBasicParseOptions + Get + Return _scanner.Options + End Get + End Property + Friend ReadOnly Property IsScript As Boolean Get Return _scanner.Options.Kind = SourceCodeKind.Script diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb index 78a47f4eb237c..87034af48384e 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb @@ -7,15 +7,15 @@ ' code-generated into SyntaxNodes.vb, but some are easier to hand-write. '----------------------------------------------------------------------------------------------------------- -Imports System.Threading +Imports System.Collections.Immutable +Imports System.ComponentModel Imports System.Text +Imports System.Threading +Imports Microsoft.CodeAnalysis.Syntax Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts Imports InternalSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax -Imports Microsoft.CodeAnalysis.Syntax -Imports System.Collections.Immutable -Imports System.ComponentModel Namespace Microsoft.CodeAnalysis.VisualBasic @@ -186,7 +186,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic disallowGenericArgumentsOnLastQualifiedName:=False, allowEmptyGenericArguments:=True, allowedEmptyGenericArguments:=True) - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), NameSyntax) + Return CreateRed(Of NameSyntax)(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node), p.Options) End Using End Function @@ -196,10 +196,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The input string ''' The starting offset in the string Public Shared Function ParseTypeName(text As String, Optional offset As Integer = 0, Optional options As ParseOptions = Nothing, Optional consumeFullText As Boolean = True) As TypeSyntax - Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(DirectCast(options, VisualBasicParseOptions), VisualBasicParseOptions.Default)) + Dim vbOptions As VisualBasicParseOptions = DirectCast(options, VisualBasicParseOptions) + Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(vbOptions, VisualBasicParseOptions.Default)) p.GetNextToken() Dim node = p.ParseGeneralType() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), TypeSyntax) + If consumeFullText Then + node = p.ConsumeUnexpectedTokens(node) + End If + Return CreateRed(Of TypeSyntax)(node, p.Options) End Using End Function @@ -223,7 +227,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) p.GetNextToken() Dim node = p.ParseExpression() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), ExpressionSyntax) + Return CreateRed(Of ExpressionSyntax)(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node), p.Options) End Using End Function @@ -235,7 +239,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Shared Function ParseExecutableStatement(text As String, Optional offset As Integer = 0, Optional consumeFullText As Boolean = True) As StatementSyntax Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) Dim node = p.ParseExecutableStatement() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), StatementSyntax) + Return CreateRed(Of StatementSyntax)(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node), p.Options) End Using End Function @@ -246,7 +250,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The starting offset in the string Public Shared Function ParseCompilationUnit(text As String, Optional offset As Integer = 0, Optional options As VisualBasicParseOptions = Nothing) As CompilationUnitSyntax Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(options, VisualBasicParseOptions.Default)) - Return DirectCast(p.ParseCompilationUnit().CreateRed(Nothing, 0), CompilationUnitSyntax) + Dim node = p.ParseCompilationUnit() + Return CreateRed(Of CompilationUnitSyntax)(node, p.Options) End Using End Function @@ -259,7 +264,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) p.GetNextToken() Dim node = p.ParseParameterList() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), ParameterListSyntax) + Return CreateRed(Of ParameterListSyntax)(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node), p.Options) End Using End Function @@ -272,7 +277,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) p.GetNextToken() Dim node = p.ParseParenthesizedArguments() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), ArgumentListSyntax) + Return CreateRed(Of ArgumentListSyntax)(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node), p.Options) End Using End Function @@ -298,15 +303,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim xmlName = InternalSyntax.SyntaxFactory.XmlName( Nothing, InternalSyntax.SyntaxFactory.XmlNameToken(parentElementName, SyntaxKind.XmlNameToken, Nothing, Nothing)) - Return DirectCast( - parser.ParseXmlAttribute( + Dim xmlAttribute = parser.ParseXmlAttribute( requireLeadingWhitespace:=False, AllowNameAsExpression:=False, - xmlElementName:=xmlName).CreateRed(Nothing, 0), BaseXmlAttributeSyntax) + xmlElementName:=xmlName) + Return CreateRed(Of BaseXmlAttributeSyntax)(xmlAttribute, scanner.Options) End Using End Using End Function + Private Shared Function CreateRed(Of TSyntax As VisualBasicSyntaxNode)(green As InternalSyntax.VisualBasicSyntaxNode, options As VisualBasicParseOptions) As TSyntax + Dim red = DirectCast(green.CreateRed(), TSyntax) + Debug.Assert(red._syntaxTree Is Nothing) +#Disable Warning RS0030 ' Do not use banned APIs (CreateWithoutClone is intended to be used from this call site) + red._syntaxTree = VisualBasicSyntaxTree.CreateWithoutClone(red, options) +#Enable Warning RS0030 + Return red + End Function + #End Region #Region "TokenFactories" diff --git a/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxNode.vb b/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxNode.vb index ae5c84381bf04..3d8e5229b22de 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxNode.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxNode.vb @@ -2,12 +2,8 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.Collections.ObjectModel -Imports System.ComponentModel -Imports System.Reflection Imports System.Threading -Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -70,8 +66,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If tree Is Nothing Then Debug.Assert(rootCandidate IsNot Nothing) -#Disable Warning RS0030 ' Do not use banned APIs (CreateWithoutClone is intended to be used from this call site only) - tree = VisualBasicSyntaxTree.CreateWithoutClone(DirectCast(rootCandidate, VisualBasicSyntaxNode)) +#Disable Warning RS0030 ' Do not use banned APIs (CreateWithoutClone is intended to be used from this call site) + tree = VisualBasicSyntaxTree.CreateWithoutClone(DirectCast(rootCandidate, VisualBasicSyntaxNode), VisualBasicParseOptions.Default) #Enable Warning RS0030 End If diff --git a/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxTree.vb b/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxTree.vb index 04ed895f802ff..2f1d0ef1c6f64 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxTree.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/VisualBasicSyntaxTree.vb @@ -210,10 +210,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Internal helper for class to create a new syntax tree rooted at the given root node. ''' This method does not create a clone of the given root, but instead preserves its reference identity. ''' - ''' NOTE: This method is only intended to be used from property. + ''' NOTE: This method is only intended to be used from property and SyntaxFactory.Parse* methods. ''' NOTE: Do not use this method elsewhere, instead use method for creating a syntax tree. ''' - Friend Shared Function CreateWithoutClone(root As VisualBasicSyntaxNode) As SyntaxTree + Friend Shared Function CreateWithoutClone(root As VisualBasicSyntaxNode, options As VisualBasicParseOptions) As SyntaxTree Debug.Assert(root IsNot Nothing) Return New ParsedSyntaxTree( @@ -221,7 +221,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic path:="", encodingOpt:=Nothing, checksumAlgorithm:=SourceHashAlgorithm.Sha1, - options:=VisualBasicParseOptions.Default, + options:=options, syntaxRoot:=root, isMyTemplate:=False, diagnosticOptions:=Nothing, diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb index 12c757cc2435f..65edb50b216ab 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb @@ -45,31 +45,17 @@ F(Function() Dim semanticModel = compilation.GetSemanticModel(syntaxTree, True) Dim node5 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) - Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol) + Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString()) - compilation.AssertTheseDiagnostics( - -BC30420: 'Sub Main' was not found in 'Errors_01'. -BC30001: Statement is not valid in a namespace. -System.Console.WriteLine(1) -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - ) + compilation.AssertTheseDiagnostics() compilation = CreateCompilationWithMscorlib461({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script"), assemblyName:="Errors_01") semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) - Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol) + Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString()) - compilation.AssertTheseDiagnostics( - -BC30420: 'Sub Main' was not found in 'Errors_01'. -BC30001: Statement is not valid in a namespace. -System.Console.WriteLine(1) -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - ) + compilation.AssertTheseDiagnostics() syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe) @@ -129,6 +115,7 @@ BC2014: the value 'Nothing' is invalid for option 'ScriptClassName' + Public Sub Errors_02() Dim compilationUnit = VisualBasic.SyntaxFactory.ParseCompilationUnit("System.Console.WriteLine(1)", options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) Dim syntaxTree1 = compilationUnit.SyntaxTree @@ -138,33 +125,41 @@ BC2014: the value 'Nothing' is invalid for option 'ScriptClassName' Dim node2 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree2) Assert.Equal("WriteLine", node2.Name.ToString()) - Dim compilation = CreateCompilationWithMscorlib461({syntaxTree1, syntaxTree2}) - Dim semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) - Dim semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) - Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) - Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString()) + Assert.Throws(Of InvalidOperationException)( + Sub() + Dim compilation = CreateCompilationWithMscorlib461({syntaxTree1, syntaxTree2}) + Dim semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) + Dim semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) - compilation.AssertTheseDiagnostics( + Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) + Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString()) + + Compilation.AssertTheseDiagnostics( BC30001: Statement is not valid in a namespace. System.Console.WriteLine(1) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ) + ) + End Sub) - compilation = CreateCompilationWithMscorlib461({syntaxTree2, syntaxTree1}) - semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) - semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) - Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) - Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString()) + Assert.Throws(Of InvalidOperationException)( + Sub() + Dim compilation = CreateCompilationWithMscorlib461({syntaxTree2, syntaxTree1}) + Dim semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) + Dim semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) - compilation.AssertTheseDiagnostics( - + Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) + Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString()) + + Compilation.AssertTheseDiagnostics( + BC30001: Statement is not valid in a namespace. System.Console.WriteLine(1) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ) + ) + End Sub) End Sub Private Shared Function ErrorTestsGetNode(syntaxTree As SyntaxTree) As MemberAccessExpressionSyntax diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/SyntaxTreeRootTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/SyntaxTreeRootTests.vb index 76cdf5c630995..7024c5bc413f6 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/SyntaxTreeRootTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/SyntaxTreeRootTests.vb @@ -3,7 +3,6 @@ ' See the LICENSE file in the project root for more information. Imports System.Reflection -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -19,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics Public Sub SyntaxTreeCreateWithoutCloneAcceptsAnySyntaxNode() Dim node As VisualBasicSyntaxNode = SyntaxFactory.CatchStatement(SyntaxFactory.IdentifierName("Goo"), SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(GetType(InvalidOperationException).Name)), Nothing) - Dim tree = VisualBasicSyntaxTree.CreateWithoutClone(node) + Dim tree = VisualBasicSyntaxTree.CreateWithoutClone(node, VisualBasicParseOptions.Default) CheckTree(tree) End Sub diff --git a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb index 62f091c35ccd5..bb08faf2730a6 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb @@ -123,5 +123,16 @@ Integer Dim type2 = SyntaxFactory.ParseTypeName(code, options:=options) Assert.Equal("Integer", type2.ToString()) End Sub + + + Public Shared Sub TestParseMethodsKeepParseOptionsInTheTree() + Dim parseOptions = VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest) + + Dim compUnit = SyntaxFactory.ParseCompilationUnit("", options:=parseOptions) + Assert.Same(parseOptions, compUnit.SyntaxTree.Options) + + Dim typeName = SyntaxFactory.ParseTypeName("", options:=parseOptions) + Assert.Same(parseOptions, typeName.SyntaxTree.Options) + End Sub End Class End Namespace