提交 b4b6b45e 编写于 作者: A AlekseyTs 提交者: GitHub

Merge pull request #16887 from AlekseyTs/Issue10023_2

Harden compilers against misplaced global code plus some clean-up around ScriptClass.
......@@ -1181,13 +1181,7 @@ internal new NamedTypeSymbol ScriptClass
/// <returns>The Script class symbol or null if it is not defined.</returns>
private ImplicitNamedTypeSymbol BindScriptClass()
{
if (_options.ScriptClassName == null || !_options.ScriptClassName.IsValidClrTypeName())
{
return null;
}
var namespaceOrType = this.Assembly.GlobalNamespace.GetNamespaceOrTypeByQualifiedName(_options.ScriptClassName.Split('.')).AsSingleton();
return namespaceOrType as ImplicitNamedTypeSymbol;
return (ImplicitNamedTypeSymbol)CommonBindScriptClass();
}
internal bool IsSubmissionSyntaxTree(SyntaxTree tree)
......
......@@ -1063,10 +1063,11 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
case SyntaxKind.GlobalStatement:
{
Debug.Assert(!this.IsRegularCSharp);
var parent = node.Parent;
// TODO (tomat): handle misplaced global statements
if (parent.Kind() == SyntaxKind.CompilationUnit)
if (parent.Kind() == SyntaxKind.CompilationUnit &&
!this.IsRegularCSharp &&
(object)_compilation.ScriptClass != null)
{
var scriptInitializer = _compilation.ScriptClass.GetScriptInitializer();
Debug.Assert((object)scriptInitializer != null);
......
......@@ -2851,7 +2851,6 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
var firstMember = members[0];
var bodyBinder = this.GetBinder(firstMember);
bool globalCodeAllowed = IsGlobalCodeAllowed(firstMember.Parent);
ArrayBuilder<FieldOrPropertyInitializer> staticInitializers = null;
ArrayBuilder<FieldOrPropertyInitializer> instanceInitializers = null;
......@@ -2864,14 +2863,14 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
return;
}
bool reportMisplacedGlobalCode = !globalCodeAllowed && !m.HasErrors;
bool reportMisplacedGlobalCode = !m.HasErrors;
switch (m.Kind())
{
case SyntaxKind.FieldDeclaration:
{
var fieldSyntax = (FieldDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(fieldSyntax.Declaration.Variables.First().Identifier));
......@@ -2912,7 +2911,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.MethodDeclaration:
{
var methodSyntax = (MethodDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(methodSyntax.Identifier));
......@@ -2926,7 +2925,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.ConstructorDeclaration:
{
var constructorSyntax = (ConstructorDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(constructorSyntax.Identifier));
......@@ -2940,7 +2939,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.DestructorDeclaration:
{
var destructorSyntax = (DestructorDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(destructorSyntax.Identifier));
......@@ -2958,7 +2957,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.PropertyDeclaration:
{
var propertySyntax = (PropertyDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(propertySyntax.Identifier));
......@@ -3008,7 +3007,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.EventFieldDeclaration:
{
var eventFieldSyntax = (EventFieldDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(
ErrorCode.ERR_NamespaceUnexpected,
......@@ -3060,7 +3059,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.EventDeclaration:
{
var eventSyntax = (EventDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(eventSyntax.Identifier));
......@@ -3080,7 +3079,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.IndexerDeclaration:
{
var indexerSyntax = (IndexerDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(indexerSyntax.ThisKeyword));
......@@ -3097,7 +3096,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.ConversionOperatorDeclaration:
{
var conversionOperatorSyntax = (ConversionOperatorDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(conversionOperatorSyntax.OperatorKeyword));
......@@ -3112,7 +3111,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.OperatorDeclaration:
{
var operatorSyntax = (OperatorDeclarationSyntax)m;
if (reportMisplacedGlobalCode)
if (IsImplicitClass && reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_NamespaceUnexpected,
new SourceLocation(operatorSyntax.OperatorKeyword));
......@@ -3128,10 +3127,6 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.GlobalStatement:
{
var globalStatement = ((GlobalStatementSyntax)m).Statement;
if (reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_GlobalStatement, new SourceLocation(globalStatement));
}
if (IsScriptClass)
{
......@@ -3175,9 +3170,13 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
// no other statement introduces variables into the enclosing scope
break;
}
}
AddInitializer(ref instanceInitializers, ref builder.InstanceSyntaxLength, null, globalStatement);
AddInitializer(ref instanceInitializers, ref builder.InstanceSyntaxLength, null, globalStatement);
}
else if (reportMisplacedGlobalCode)
{
diagnostics.Add(ErrorCode.ERR_GlobalStatement, new SourceLocation(globalStatement));
}
}
break;
......@@ -3194,13 +3193,6 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
AddInitializers(builder.StaticInitializers, staticInitializers);
}
private static bool IsGlobalCodeAllowed(CSharpSyntaxNode parent)
{
var parentKind = parent.Kind();
return !(parentKind == SyntaxKind.NamespaceDeclaration ||
parentKind == SyntaxKind.CompilationUnit && parent.SyntaxTree.Options.Kind == SourceCodeKind.Regular);
}
private void AddAccessorIfAvailable(ArrayBuilder<Symbol> symbols, MethodSymbol accessorOpt, DiagnosticBag diagnostics, bool checkName = false)
{
if ((object)accessorOpt != null)
......
......@@ -958,5 +958,215 @@ public void FixedBuffer_02()
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[3]").WithLocation(1, 11)
);
}
[Fact]
[WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")]
public void Errors_01()
{
var code = "System.Console.WriteLine(1);";
var compilationUnit = CSharp.SyntaxFactory.ParseCompilationUnit(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
var syntaxTree = compilationUnit.SyntaxTree;
var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree });
var semanticModel = compilation.GetSemanticModel(syntaxTree, true);
MemberAccessExpressionSyntax node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
compilation.VerifyDiagnostics(
// (1,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(1);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(1, 1)
);
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
compilation.VerifyDiagnostics(
// (1,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(1);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(1, 1),
// error CS5001: Program does not contain a static 'Main' method suitable for an entry point
Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)
);
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe);
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput:"1").VerifyDiagnostics();
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "1").VerifyDiagnostics();
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName(""));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// error CS7088: Invalid 'ScriptClassName' value: ''.
Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("ScriptClassName", "").WithLocation(1, 1)
);
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName(null));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// error CS7088: Invalid 'ScriptClassName' value: 'null'.
Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("ScriptClassName", "null")
);
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("a\0b"));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// error CS7088: Invalid 'ScriptClassName' value: 'a\0b'.
Diagnostic(ErrorCode.ERR_BadCompilationOptionValue).WithArguments("ScriptClassName", "a\0b")
);
}
[Fact]
[WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")]
public void Errors_02()
{
var compilationUnit = CSharp.SyntaxFactory.ParseCompilationUnit("\nSystem.Console.WriteLine(1);", options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
var syntaxTree1 = compilationUnit.SyntaxTree;
var syntaxTree2 = SyntaxFactory.ParseSyntaxTree("System.Console.WriteLine(2);", options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
MemberAccessExpressionSyntax node1 = ErrorTestsGetNode(syntaxTree1);
MemberAccessExpressionSyntax node2 = ErrorTestsGetNode(syntaxTree2);
Assert.Equal("WriteLine", node1.Name.ToString());
Assert.Equal("WriteLine", node2.Name.ToString());
var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree1, syntaxTree2 });
var semanticModel1 = compilation.GetSemanticModel(syntaxTree1, true);
var semanticModel2 = compilation.GetSemanticModel(syntaxTree2, true);
Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol);
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// (2,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(1);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(2, 1)
);
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree2, syntaxTree1 });
semanticModel1 = compilation.GetSemanticModel(syntaxTree1, true);
semanticModel2 = compilation.GetSemanticModel(syntaxTree2, true);
Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol);
Assert.Equal("void System.Console.WriteLine(System.Int32 value)", semanticModel2.GetSymbolInfo(node2.Name).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// (2,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(1);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(2, 1)
);
}
[Fact]
[WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")]
public void Errors_03()
{
var code = "System.Console.WriteLine(out var x, x);";
var compilationUnit = CSharp.SyntaxFactory.ParseCompilationUnit(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
var syntaxTree = compilationUnit.SyntaxTree;
var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree });
var semanticModel = compilation.GetSemanticModel(syntaxTree, true);
MemberAccessExpressionSyntax node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
var x = syntaxTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
Assert.Null(semanticModel.GetSymbolInfo(x).Symbol);
compilation.VerifyDiagnostics(
// (1,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(out var x, x);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(out var x, x);").WithLocation(1, 1)
);
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1"));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
compilation.VerifyDiagnostics(
// (1,1): error CS7006: Expressions and statements can only occur in a method body
// System.Console.WriteLine(out var x, x);
Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(out var x, x);").WithLocation(1, 1),
// error CS5001: Program does not contain a static 'Main' method suitable for an entry point
Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)
);
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree });
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
x = syntaxTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
Assert.Equal("var Script.x", semanticModel.GetSymbolInfo(x).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// (1,34): error CS7019: Type of 'x' cannot be inferred since its initializer directly or indirectly refers to the definition.
// System.Console.WriteLine(out var x, x);
Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x").WithArguments("x").WithLocation(1, 34)
);
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script));
compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1"));
semanticModel = compilation.GetSemanticModel(syntaxTree, true);
node5 = ErrorTestsGetNode(syntaxTree);
Assert.Equal("WriteLine", node5.Name.ToString());
Assert.Null(semanticModel.GetSymbolInfo(node5.Name).Symbol);
x = syntaxTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
Assert.Equal("var Script1.x", semanticModel.GetSymbolInfo(x).Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// (1,34): error CS7019: Type of 'x' cannot be inferred since its initializer directly or indirectly refers to the definition.
// System.Console.WriteLine(out var x, x);
Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x").WithArguments("x").WithLocation(1, 34)
);
}
[Fact]
[WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")]
public void NoNeedToTestSourceCodeKindInteractive()
{
#pragma warning disable CS0618
Assert.Throws<ArgumentOutOfRangeException>(() => new CSharp.CSharpParseOptions(kind: SourceCodeKind.Interactive));
#pragma warning restore CS0618
}
private static MemberAccessExpressionSyntax ErrorTestsGetNode(SyntaxTree syntaxTree)
{
var node1 = (CompilationUnitSyntax)syntaxTree.GetRoot();
var node2 = (GlobalStatementSyntax)node1.Members.First();
var node3 = (ExpressionStatementSyntax)node2.Statement;
var node4 = (InvocationExpressionSyntax)node3.Expression;
var node5 = (MemberAccessExpressionSyntax)node4.Expression;
return node5;
}
}
}
......@@ -823,6 +823,51 @@ public INamedTypeSymbol GetSpecialType(SpecialType specialType)
public INamedTypeSymbol ScriptClass { get { return CommonScriptClass; } }
protected abstract INamedTypeSymbol CommonScriptClass { get; }
/// <summary>
/// Resolves a symbol that represents script container (Script class). Uses the
/// full name of the container class stored in <see cref="CompilationOptions.ScriptClassName"/> to find the symbol.
/// </summary>
/// <returns>The Script class symbol or null if it is not defined.</returns>
protected INamedTypeSymbol CommonBindScriptClass()
{
string scriptClassName = this.Options.ScriptClassName ?? "";
string[] parts = scriptClassName.Split('.');
INamespaceSymbol container = this.SourceModule.GlobalNamespace;
for (int i = 0; i < parts.Length - 1; i++)
{
INamespaceSymbol next = container.GetNestedNamespace(parts[i]);
if (next == null)
{
AssertNoScriptTrees();
return null;
}
container = next;
}
foreach (INamedTypeSymbol candidate in container.GetTypeMembers(parts[parts.Length - 1]))
{
if (candidate.IsScriptClass)
{
return candidate;
}
}
AssertNoScriptTrees();
return null;
}
[Conditional("DEBUG")]
private void AssertNoScriptTrees()
{
foreach (var tree in this.SyntaxTrees)
{
Debug.Assert(tree.Options.Kind != SourceCodeKind.Script);
}
}
/// <summary>
/// Returns a new ArrayTypeSymbol representing an array type tied to the base types of the
/// COR Library in this Compilation.
......
......@@ -88,5 +88,17 @@ internal static string ProvidedTupleElementNameOrNull(this IFieldSymbol field)
return field.IsTupleElement() && !field.IsImplicitlyDeclared ? field.Name : null;
}
internal static INamespaceSymbol GetNestedNamespace(this INamespaceSymbol container, string name)
{
foreach (var sym in container.GetMembers(name))
{
if (sym.Kind == SymbolKind.Namespace)
{
return (INamespaceSymbol)sym;
}
}
return null;
}
}
}
......@@ -93,9 +93,10 @@ Friend Module CompilationUtils
Public Function CreateCompilationWithMscorlib45(sourceTrees As IEnumerable(Of SyntaxTree),
Optional references As IEnumerable(Of MetadataReference) = Nothing,
Optional options As VisualBasicCompilationOptions = Nothing) As VisualBasicCompilation
Optional options As VisualBasicCompilationOptions = Nothing,
Optional assemblyName As String = Nothing) As VisualBasicCompilation
Dim additionalRefs = {MscorlibRef_v4_0_30316_17626}
Return VisualBasicCompilation.Create(GetUniqueName(), sourceTrees, If(references Is Nothing, additionalRefs, additionalRefs.Concat(references)), options)
Return VisualBasicCompilation.Create(If(assemblyName, GetUniqueName()), sourceTrees, If(references Is Nothing, additionalRefs, additionalRefs.Concat(references)), options)
End Function
Public Function CreateCompilationWithMscorlib45AndVBRuntime(sourceTrees As IEnumerable(Of SyntaxTree),
......
......@@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public Shared Function CreateBinderForSourceFileImports(moduleSymbol As SourceModuleSymbol,
tree As SyntaxTree) As Binder
Dim sourceModuleBinder As Binder = CreateSourceModuleBinder(moduleSymbol)
Dim sourceFileBinder As Binder = New SourceFileBinder(sourceModuleBinder, moduleSymbol.GetSourceFile(tree), tree)
Dim sourceFileBinder As Binder = New SourceFileBinder(sourceModuleBinder, moduleSymbol.TryGetSourceFile(tree), tree)
Dim namespaceBinder As Binder = New NamespaceBinder(sourceFileBinder, moduleSymbol.ContainingSourceAssembly.DeclaringCompilation.GlobalNamespace)
Dim ignoreBasesBinder As Binder = New IgnoreBaseClassesBinder(namespaceBinder)
......@@ -101,7 +101,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
moduleBinder = New XmlNamespaceImportsBinder(moduleBinder, projectXmlNamespaces)
End If
Dim sourceFile = moduleSymbol.GetSourceFile(tree)
Dim sourceFile = moduleSymbol.TryGetSourceFile(tree)
If sourceFile Is Nothing Then
Return moduleBinder
End If
Dim sourceFileBinder As Binder = New SourceFileBinder(moduleBinder, sourceFile, tree)
' Add file-level member imports.
......
......@@ -26,6 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public Sub New(containingBinder As Binder, sourceFile As SourceFile, tree As SyntaxTree)
MyBase.New(containingBinder, tree)
Debug.Assert(sourceFile IsNot Nothing)
_sourceFile = sourceFile
End Sub
......
......@@ -1542,8 +1542,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata
' and we don't want to emit different metadata depending on whether or we emit with PDB stream.
' TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class.
Dim importScopeOpt = If(method.Syntax IsNot Nothing AndAlso method.Syntax.SyntaxTree IsNot VisualBasicSyntaxTree.DummySyntaxTree.Dummy,
moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree).Translate(moduleBuilder, diagnostics),
Dim importScopeOpt = If(method.Syntax IsNot Nothing,
moduleBuilder.SourceModule.TryGetSourceFile(method.Syntax.SyntaxTree)?.Translate(moduleBuilder, diagnostics),
Nothing)
If diagnostics.HasAnyErrors() Then
......
......@@ -1318,7 +1318,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim aliasName As String = declarationSyntax.Alias.Identifier.ValueText
If Not String.IsNullOrEmpty(aliasName) Then
Dim sourceFile = Me._sourceModule.GetSourceFile(Me.SyntaxTree)
Dim sourceFile = Me._sourceModule.TryGetSourceFile(Me.SyntaxTree)
Debug.Assert(sourceFile IsNot Nothing)
Dim aliasImports As IReadOnlyDictionary(Of String, AliasAndImportsClausePosition) = sourceFile.AliasImportsOpt
Dim symbol As AliasAndImportsClausePosition = Nothing
......
......@@ -1770,12 +1770,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' The Script class symbol or null if it is not defined.
''' </returns>
Private Function BindScriptClass() As ImplicitNamedTypeSymbol
If Options.ScriptClassName Is Nothing OrElse Not Options.ScriptClassName.IsValidClrTypeName() Then
Return Nothing
End If
Dim namespaceOrType = Me.Assembly.GlobalNamespace.GetNamespaceOrTypeByQualifiedName(Options.ScriptClassName.Split("."c)).AsSingleton()
Return TryCast(namespaceOrType, ImplicitNamedTypeSymbol)
Return DirectCast(CommonBindScriptClass(), ImplicitNamedTypeSymbol)
End Function
''' <summary>
......
......@@ -159,7 +159,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim compilation = semanticModelOpt.Compilation
Dim sourceModule = DirectCast(compilation.SourceModule, SourceModuleSymbol)
Dim sourceFile = sourceModule.GetSourceFile(DirectCast(GetSyntaxTree(DirectCast(semanticModelOpt, SemanticModel)), VisualBasicSyntaxTree))
Dim sourceFile = sourceModule.TryGetSourceFile(DirectCast(GetSyntaxTree(DirectCast(semanticModelOpt, SemanticModel)), VisualBasicSyntaxTree))
Debug.Assert(sourceFile IsNot Nothing)
If Not sourceFile.AliasImportsOpt Is Nothing Then
For Each [alias] In sourceFile.AliasImportsOpt.Values
......
......@@ -2608,17 +2608,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
CreateEvent(eventDecl.EventStatement, eventDecl, binder, diagBag, members)
Case Else
If binder.BindingTopLevelScriptCode Then
If memberSyntax.Kind = SyntaxKind.EmptyStatement OrElse TypeOf memberSyntax Is ExecutableStatementSyntax Then
If reportAsInvalid Then
diagBag.Add(ERRID.ERR_InvalidInNamespace, memberSyntax.GetLocation())
End If
If memberSyntax.Kind = SyntaxKind.EmptyStatement OrElse TypeOf memberSyntax Is ExecutableStatementSyntax Then
If binder.BindingTopLevelScriptCode Then
Debug.Assert(Not reportAsInvalid)
Dim initializer = Function(precedingInitializersLength As Integer)
Return New FieldOrPropertyInitializer(binder.GetSyntaxReference(memberSyntax), precedingInitializersLength)
End Function
SourceNamedTypeSymbol.AddInitializer(instanceInitializers, initializer, members.InstanceSyntaxLength)
ElseIf reportAsInvalid Then
diagBag.Add(ERRID.ERR_InvalidInNamespace, memberSyntax.GetLocation())
End If
End If
End Select
......
......@@ -154,17 +154,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
' Get the SourceFile object associated with a root declaration.
Friend Function GetSourceFile(tree As SyntaxTree) As SourceFile
''' <summary>
''' Get the SourceFile object associated with a root declaration.
''' Returns Nothing if the tree doesn't belong to the compilation.
''' </summary>
Friend Function TryGetSourceFile(tree As SyntaxTree) As SourceFile
Debug.Assert(tree IsNot Nothing)
Debug.Assert(tree.IsEmbeddedOrMyTemplateTree() OrElse _assemblySymbol.DeclaringCompilation.SyntaxTrees.Contains(tree))
Dim srcFile As SourceFile = Nothing
If _sourceFileMap.TryGetValue(tree, srcFile) Then
Return srcFile
Else
ElseIf _assemblySymbol.DeclaringCompilation.AllSyntaxTrees.Contains(tree) Then
srcFile = New SourceFile(Me, tree)
Return _sourceFileMap.GetOrAdd(tree, srcFile)
Else
Return Nothing
End If
End Function
......@@ -536,7 +542,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Dim builder = ArrayBuilder(Of Diagnostic).GetInstance()
' Force source file to generate errors for Imports and the like.
Dim sourceFile As SourceFile = GetSourceFile(tree)
Dim sourceFile As SourceFile = TryGetSourceFile(tree)
Debug.Assert(sourceFile IsNot Nothing)
If filterSpanWithinTree.HasValue Then
Dim diagnostics = sourceFile.GetDeclarationErrorsInSpan(filterSpanWithinTree.Value, cancellationToken)
diagnostics = locationFilter(diagnostics, tree, filterSpanWithinTree)
......@@ -610,13 +618,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
UICultureUtilities.WithCurrentUICulture(
Sub(i As Integer)
cancellationToken.ThrowIfCancellationRequested()
GetSourceFile(trees(i)).GenerateAllDeclarationErrors()
TryGetSourceFile(trees(i)).GenerateAllDeclarationErrors()
End Sub))
trees.Free()
Else
For Each tree In SyntaxTrees
cancellationToken.ThrowIfCancellationRequested()
GetSourceFile(tree).GenerateAllDeclarationErrors()
TryGetSourceFile(tree).GenerateAllDeclarationErrors()
Next
End If
......@@ -662,7 +670,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
builder.AddRange(Me._lazyLinkedAssemblyDiagnostics)
For Each tree In SyntaxTrees
builder.AddRange(GetSourceFile(tree).DeclarationErrors)
builder.AddRange(TryGetSourceFile(tree).DeclarationErrors)
Next
Return builder.ToReadOnlyAndFree(Of Diagnostic)()
......@@ -996,7 +1004,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Dim loc = d.Location
If loc.IsInSource Then
Dim tree = DirectCast(loc.SourceTree, VisualBasicSyntaxTree)
Dim sourceFile = GetSourceFile(tree)
Dim sourceFile = TryGetSourceFile(tree)
Debug.Assert(sourceFile IsNot Nothing)
sourceFile.AddDiagnostic(d, stage)
Else
Me.AddDiagnostic(d, stage)
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
......@@ -30,6 +31,155 @@ F(Function()
~~~~~~~~~~~
</errors>)
End Sub
<Fact>
<WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")>
Public Sub Errors_01()
Dim code = "System.Console.WriteLine(1)"
Dim compilationUnit = VisualBasic.SyntaxFactory.ParseCompilationUnit(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
Dim syntaxTree = compilationUnit.SyntaxTree
Dim compilation = CreateCompilationWithMscorlib45({syntaxTree}, assemblyName:="Errors_01")
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)
compilation.AssertTheseDiagnostics(
<expected>
BC30420: 'Sub Main' was not found in 'Errors_01'.
BC30001: Statement is not valid in a namespace.
System.Console.WriteLine(1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
</expected>
)
compilation = CreateCompilationWithMscorlib45({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)
compilation.AssertTheseDiagnostics(
<expected>
BC30420: 'Sub Main' was not found in 'Errors_01'.
BC30001: Statement is not valid in a namespace.
System.Console.WriteLine(1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
</expected>
)
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree})
semanticModel = compilation.GetSemanticModel(syntaxTree, True)
node5 = ErrorTestsGetNode(syntaxTree)
Assert.Equal("WriteLine", node5.Name.ToString())
Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString())
CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics()
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script"))
semanticModel = compilation.GetSemanticModel(syntaxTree, True)
node5 = ErrorTestsGetNode(syntaxTree)
Assert.Equal("WriteLine", node5.Name.ToString())
Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString())
CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics()
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName(""))
semanticModel = compilation.GetSemanticModel(syntaxTree, True)
node5 = ErrorTestsGetNode(syntaxTree)
Assert.Equal("WriteLine", node5.Name.ToString())
Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString())
compilation.AssertTheseDiagnostics(
<expected>
BC2014: the value '' is invalid for option 'ScriptClassName'
</expected>
)
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName(Nothing))
semanticModel = compilation.GetSemanticModel(syntaxTree, True)
node5 = ErrorTestsGetNode(syntaxTree)
Assert.Equal("WriteLine", node5.Name.ToString())
Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString())
compilation.AssertTheseDiagnostics(
<expected>
BC2014: the value 'Nothing' is invalid for option 'ScriptClassName'
</expected>
)
syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("a" + ChrW(0) + "b"))
semanticModel = compilation.GetSemanticModel(syntaxTree, True)
node5 = ErrorTestsGetNode(syntaxTree)
Assert.Equal("WriteLine", node5.Name.ToString())
Assert.Equal("Sub System.Console.WriteLine(value As System.Int32)", semanticModel.GetSymbolInfo(node5.Name).Symbol.ToTestDisplayString())
compilation.VerifyDiagnostics(
Diagnostic(ERRID.ERR_InvalidSwitchValue).WithArguments("ScriptClassName", "a" + ChrW(0) + "b").WithLocation(1, 1)
)
End Sub
<Fact>
<WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")>
Public Sub Errors_02()
Dim compilationUnit = VisualBasic.SyntaxFactory.ParseCompilationUnit("System.Console.WriteLine(1)", options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
Dim syntaxTree1 = compilationUnit.SyntaxTree
Dim syntaxTree2 = SyntaxFactory.ParseSyntaxTree("System.Console.WriteLine(2)", options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script))
Dim node1 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree1)
Assert.Equal("WriteLine", node1.Name.ToString())
Dim node2 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree2)
Assert.Equal("WriteLine", node2.Name.ToString())
Dim compilation = CreateCompilationWithMscorlib45({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())
compilation.AssertTheseDiagnostics(
<expected>
BC30001: Statement is not valid in a namespace.
System.Console.WriteLine(1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
</expected>
)
compilation = CreateCompilationWithMscorlib45({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())
compilation.AssertTheseDiagnostics(
<expected>
BC30001: Statement is not valid in a namespace.
System.Console.WriteLine(1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
</expected>
)
End Sub
Private Shared Function ErrorTestsGetNode(syntaxTree As SyntaxTree) As MemberAccessExpressionSyntax
Dim node1 = DirectCast(syntaxTree.GetRoot(), CompilationUnitSyntax)
Dim node3 = DirectCast(node1.Members.First(), ExpressionStatementSyntax)
Dim node4 = DirectCast(node3.Expression, InvocationExpressionSyntax)
Dim node5 = DirectCast(node4.Expression, MemberAccessExpressionSyntax)
Return node5
End Function
<Fact>
<WorkItem(10023, "https://github.com/dotnet/roslyn/issues/10023")>
Public Sub NoNeedToTestSourceCodeKindInteractive()
#Disable Warning BC40000
Assert.Throws(Of ArgumentOutOfRangeException)(Function() New VisualBasicParseOptions(kind:=SourceCodeKind.Interactive))
#Enable Warning BC40000
End Sub
End Class
End Namespace
......@@ -125,6 +125,20 @@ End Namespace
Assert.False(root.IsGlobalNamespace)
End Sub
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/16885")>
<WorkItem(16885, "https://github.com/dotnet/roslyn/issues/16885")>
Public Sub RootNamespace_NoTrees_SuppressEmbeddedDeclarations()
Dim c1 = VisualBasicCompilation.Create("Test", {}, options:=TestOptions.ReleaseDll.WithRootNamespace("A.B.C").WithSuppressEmbeddedDeclarations(True))
Dim root As NamespaceSymbol = c1.RootNamespace
Assert.NotNull(root)
Assert.Equal("C", root.Name)
Assert.Equal("B", root.ContainingNamespace.Name)
Assert.Equal("A", root.ContainingNamespace.ContainingNamespace.Name)
Assert.False(root.IsGlobalNamespace)
End Sub
<Fact()>
Public Sub RootNamespace_WithFiles_UpdateCompilation()
Dim sourceTree = ParserTestUtilities.Parse(
......
......@@ -57,8 +57,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim originalCompilation = compilation
If syntax IsNot Nothing Then
compilation = compilation.AddSyntaxTrees(syntax.SyntaxTree)
If syntax IsNot Nothing AndAlso compilation.Options.SuppressEmbeddedDeclarations AndAlso
compilation.SyntaxTrees.IsEmpty Then
' We need to add an empty tree to the compilation as
' a workaround for https://github.com/dotnet/roslyn/issues/16885.
compilation = compilation.AddSyntaxTrees(VisualBasicSyntaxTree.Dummy)
End If
Dim defaultNamespaceName As String = methodDebugInfo.DefaultNamespaceName
......
......@@ -109,7 +109,7 @@ End Class"
errorMessage,
testData)
Assert.Equal(testData.Methods.Count, 2)
Assert.Equal(testData.Methods.Count, 1)
testData.GetMethodData("<>x.<>m0").VerifyIL(
"{
// Code size 78 (0x4e)
......
......@@ -358,7 +358,9 @@ End Class
Dim aliases = ImmutableArray.Create(ExceptionAlias("Microsoft.CSharp.RuntimeBinder.RuntimeBinderException, Microsoft.CSharp, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a", stowed:=True))
Const expectedError = "error BC30002: Type 'System.Void' is not defined."
Const expectedError = "error BC30652: Reference required to assembly " &
"'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' " &
"containing the type 'Exception'. Add one to your project."
Dim expectedMissingAssemblyIdentity = comp.Assembly.CorLibrary.Identity
Dim resultProperties As ResultProperties = Nothing
......
......@@ -103,7 +103,7 @@ End Class
aliases,
errorMessage,
testData)
Assert.Equal(testData.Methods.Count, 2)
Assert.Equal(testData.Methods.Count, 1)
testData.GetMethodData("<>x.<>m0").VerifyIL(
"{
......@@ -395,7 +395,7 @@ End Class"
errorMessage:=errorMessage)
If valid Then
Dim expectedNames = {"<>x.<>m0(C)", "<invalid-global-code>..ctor()"} ' Unnecessary <invalid-global-code> (DevDiv #1010243)
Dim expectedNames = {"<>x.<>m0(C)"}
Dim actualNames = testData.GetMethodsByName().Keys
AssertEx.SetEqual(expectedNames, actualNames)
Else
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册