-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add "#error version" to C# and udpate UpgradeProject to support 7.1 #18045
Changes from all commits
3c4893f
5d81ef0
9da0117
0c04bef
da46683
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,13 @@ | |
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Test.Utilities; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Roslyn.Test.Utilities; | ||
using Xunit; | ||
|
@@ -58,7 +61,7 @@ internal struct MemberInfo | |
|
||
#endregion | ||
|
||
public class PreprocessorTests | ||
public class PreprocessorTests : TestBase | ||
{ | ||
public PreprocessorTests() | ||
{ | ||
|
@@ -182,7 +185,30 @@ private void VerifyDirectivesSpecial(CSharpSyntaxNode node, params DirectiveInfo | |
{ | ||
Assert.Equal(exp.Text, ((DefineDirectiveTriviaSyntax)dt).Name.ValueText); // Text | ||
} | ||
|
||
break; | ||
case SyntaxKind.ErrorDirectiveTrivia: | ||
if (null != exp.Text) | ||
{ | ||
Assert.Equal(exp.Text, ((ErrorDirectiveTriviaSyntax)dt).EndOfDirectiveToken.ToFullString()); | ||
} | ||
break; | ||
case SyntaxKind.LoadDirectiveTrivia: | ||
if (null != exp.Text) | ||
{ | ||
Assert.Equal(exp.Text, ((LoadDirectiveTriviaSyntax)dt).File.ValueText); | ||
} | ||
break; | ||
case SyntaxKind.UndefDirectiveTrivia: | ||
if (null != exp.Text) | ||
{ | ||
Assert.Equal(exp.Text, ((UndefDirectiveTriviaSyntax)dt).Name.ValueText); | ||
} | ||
break; | ||
case SyntaxKind.ReferenceDirectiveTrivia: | ||
if (null != exp.Text) | ||
{ | ||
Assert.Equal(exp.Text, ((ReferenceDirectiveTriviaSyntax)dt).File.ValueText); | ||
} | ||
break; | ||
case SyntaxKind.LineDirectiveTrivia: | ||
var ld = dt as LineDirectiveTriviaSyntax; | ||
|
@@ -217,7 +243,12 @@ private void VerifyDirectivesSpecial(CSharpSyntaxNode node, params DirectiveInfo | |
Assert.NotEqual(SyntaxKind.None, ld.File.Kind()); | ||
Assert.Equal(exp.Text, ld.File.Value); | ||
} | ||
|
||
break; | ||
default: | ||
if (null != exp.Text) | ||
{ | ||
Assert.True(false, String.Format("You are expecting some text in the directive, but this method doesn't know how to verify it for `{0}`.", exp.Kind)); | ||
} | ||
break; | ||
} // switch | ||
} | ||
|
@@ -2560,7 +2591,7 @@ public void TestNegUndefWithBadTokensAfterName() | |
var node = Parse(text); | ||
TestRoundTripping(node, text, false); | ||
VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "FOO(" }); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "FOO" }); | ||
} | ||
|
||
[Fact] | ||
|
@@ -2584,7 +2615,7 @@ public void TestNegUndefWithBadNumericalName() | |
var node = Parse(text); | ||
TestRoundTripping(node, text, false); | ||
VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "1234" }); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: the |
||
} | ||
|
||
[Fact] | ||
|
@@ -2962,6 +2993,71 @@ private void CheckDiagnosticStringFileName(string compilationFileName, string li | |
Assert.Equal(expectedErrorStringFileName, actualErrorStringFileName); | ||
} | ||
|
||
[Fact] | ||
public void TestErrorWithVersion() | ||
{ | ||
var text = "#error version"; | ||
var node = Parse(text, SourceCodeKind.Regular); | ||
TestRoundTripping(node, text, disallowErrors: false); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo | ||
{ | ||
Kind = SyntaxKind.ErrorDirectiveTrivia, | ||
Status = NodeStatus.IsActive, | ||
Text = "version" | ||
}); | ||
|
||
node.GetDiagnostics().Verify( | ||
// (1,8): error CS1029: #error: 'version' | ||
// #error version | ||
Diagnostic(ErrorCode.ERR_ErrorDirective, "version").WithArguments("version").WithLocation(1, 8), | ||
// (1,8): error CS8304: Compiler version: '42.42.42.42424 (<developer build>)'. Language version: 4. | ||
// #error version | ||
Diagnostic(ErrorCode.ERR_CompilerAndLanguageVersion, "version").WithArguments(GetExpectedVersion(), "4").WithLocation(1, 8) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this showing language version 4? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought you were talking about the formatting ('4' vs. 4) in your previous comment :-S The reason is because private CSharpParseOptions GetOptions(SourceCodeKind kind, string[] defines)
{
return new CSharpParseOptions(languageVersion: LanguageVersion.CSharp4, kind: kind, preprocessorSymbols: defines);
} |
||
); | ||
} | ||
|
||
[Fact] | ||
public void TestErrorWithVersionNumber() | ||
{ | ||
var text = "#error version:7.1"; | ||
var node = Parse(text, SourceCodeKind.Regular); | ||
TestRoundTripping(node, text, disallowErrors: false); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo | ||
{ | ||
Kind = SyntaxKind.ErrorDirectiveTrivia, | ||
Status = NodeStatus.IsActive, | ||
Text = "version:7.1" | ||
}); | ||
|
||
node.GetDiagnostics().Verify( | ||
// (1,8): error CS1029: #error: 'version:7.1' | ||
// #error version:7.1 | ||
Diagnostic(ErrorCode.ERR_ErrorDirective, "version:7.1").WithArguments("version:7.1"), | ||
// (1,8): error CS8025: Feature 'version' is not available in C# 4. Please use language version 7.1 or greater. | ||
// #error version:7.1 | ||
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion4, "version:7.1").WithArguments("version", "7.1").WithLocation(1, 8) | ||
); | ||
} | ||
|
||
[Fact] | ||
public void TestErrorWithInvalidVersion() | ||
{ | ||
var text = "#error version:A.B"; | ||
var node = Parse(text, SourceCodeKind.Regular); | ||
TestRoundTripping(node, text, disallowErrors: false); | ||
VerifyDirectivesSpecial(node, new DirectiveInfo | ||
{ | ||
Kind = SyntaxKind.ErrorDirectiveTrivia, | ||
Status = NodeStatus.IsActive, | ||
Text = "version:A.B" | ||
}); | ||
|
||
node.GetDiagnostics().Verify( | ||
// (1,8): error CS1029: #error: 'version:A.B' | ||
// #error version:A.B | ||
Diagnostic(ErrorCode.ERR_ErrorDirective, "version:A.B").WithArguments("version:A.B").WithLocation(1, 8) | ||
); | ||
} | ||
#endregion | ||
|
||
#region #line | ||
|
@@ -3874,5 +3970,13 @@ public void TestLoadWithComment() | |
} | ||
|
||
#endregion | ||
|
||
private static string GetExpectedVersion() | ||
{ | ||
Assembly assembly = typeof(CSharpCompiler).GetTypeInfo().Assembly; | ||
string fileVersion = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version; | ||
string hash = CommonCompiler.ExtractShortCommitHash(assembly.GetCustomAttribute<CommitHashAttribute>().Hash); | ||
return $"{fileVersion} ({hash})"; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,7 @@ private async Task TestLanguageVersionUpgradedAsync( | |
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeProjectToDefault() | ||
public async Task UpgradeProjectFromCSharp6ToDefault() | ||
{ | ||
await TestLanguageVersionUpgradedAsync( | ||
@" | ||
|
@@ -55,7 +55,7 @@ void A() | |
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeProjectToCSharp7() | ||
public async Task UpgradeProjectFromCSharp6ToCSharp7() | ||
{ | ||
await TestLanguageVersionUpgradedAsync( | ||
@" | ||
|
@@ -71,6 +71,46 @@ void A() | |
index: 1); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeProjectFromCSharp7ToLatest() | ||
{ | ||
await TestLanguageVersionUpgradedAsync( | ||
@" | ||
class Program | ||
{ | ||
#error version:[|7.1|] | ||
}", | ||
LanguageVersion.Latest, | ||
new CSharpParseOptions(LanguageVersion.CSharp7)); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeProjectFromCSharp7_1ToLatest() | ||
{ | ||
await TestLanguageVersionUpgradedAsync( | ||
@" | ||
class Program | ||
{ | ||
#error version:[|7.1|] | ||
}", | ||
LanguageVersion.Latest, | ||
new CSharpParseOptions(LanguageVersion.CSharp7_1)); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeProjectFromCSharp7ToCSharp7_1() | ||
{ | ||
await TestLanguageVersionUpgradedAsync( | ||
@" | ||
class Program | ||
{ | ||
#error [|version:7.1|] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, i'm not getting what the user scenario is for this. Can you clarify? I did understand what the use of "#error version" was though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some of the bug reports we're getting are the result of using older versions of the compiler. When the compiler is hosted by a framework (asp.net, azure functions, CLI, etc) it will be convenient for troubleshooting to be able to check the compiler version with a source change. It's similar to "phpversion". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get the reason for "#error version". I'm curious what the purposes of "#error version:number" is though... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I had misread your comment. |
||
}", | ||
LanguageVersion.CSharp7_1, | ||
new CSharpParseOptions(LanguageVersion.CSharp7), | ||
index: 1); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUpgradeProject)] | ||
public async Task UpgradeAllProjectsToDefault() | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
@@ -69,7 +70,9 @@ protected bool TryGetDocumentAndSelectSpan(TestWorkspace workspace, out Document | |
|
||
protected Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, out string annotation, out TextSpan span) | ||
{ | ||
var hostDocument = workspace.Documents.Single(d => d.AnnotatedSpans.Any()); | ||
var annotatedDocuments = workspace.Documents.Where(d => d.AnnotatedSpans.Any()); | ||
Debug.Assert(!annotatedDocuments.IsEmpty(), "No annotated span found"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixes an annoyance I ran into when working on the original PR. |
||
var hostDocument = annotatedDocuments.Single(); | ||
var annotatedSpan = hostDocument.AnnotatedSpans.Single(); | ||
annotation = annotatedSpan.Key; | ||
span = annotatedSpan.Value.Single(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -138,7 +138,7 @@ Public Class ParseTree | |
Return Enumerations(enumString) | ||
End If | ||
|
||
ReportError(referencingElement, "{0} is not a valid field type", enumString) | ||
ReportError(referencingElement, "{0} is not a valid field type. You should add a node-kind entry in the syntax.xml.", enumString) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixes an annoyance I ran into when working on the original PR. |
||
Return Nothing | ||
End Function | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: the paren is parsed as part of the EndOfDirective, not the Name.