提交 82383960 编写于 作者: G Gen Lu

Merge pull request #9271 from genlu/IOpFlag

[AskMode] Put `IOperation` behind a feature flag
......@@ -2906,6 +2906,12 @@ internal bool EnableEnumArrayBlockInitialization
return sustainedLowLatency != null && sustainedLowLatency.ContainingAssembly == Assembly.CorLibrary;
}
}
internal override bool IsIOperationFeatureEnabled()
{
var options = (CSharpParseOptions)this.SyntaxTrees.FirstOrDefault()?.Options;
return options?.IsFeatureEnabled(MessageID.IDS_FeatureIOperation) ?? false;
}
private class SymbolSearcher
{
......
......@@ -112,6 +112,8 @@ internal enum MessageID
IDS_OperationCausedStackOverflow = MessageBase + 12703,
IDS_AwaitInCatchAndFinally = MessageBase + 12704,
IDS_FeatureReadonlyAutoImplementedProperties = MessageBase + 12705,
IDS_FeatureIOperation = MessageBase + 12706,
}
// Message IDs may refer to strings that need to be localized.
......@@ -149,6 +151,8 @@ internal static string RequiredFeature(this MessageID feature)
{
switch (feature)
{
case MessageID.IDS_FeatureIOperation:
return "IOperation";
default:
return null;
}
......
......@@ -892,7 +892,7 @@ public void TestReportingDiagnosticWithInvalidLocation()
{
var source1 = @"class C1 { void M() { int i = 0; i++; } }";
var source2 = @"class C2 { void M() { int i = 0; i++; } }";
var compilation = CreateCompilationWithMscorlib45(source1);
var compilation = CreateCompilationWithMscorlib45(source1, parseOptions: TestOptions.RegularWithIOperationFeature);
var anotherCompilation = CreateCompilationWithMscorlib45(source2);
var treeInAnotherCompilation = anotherCompilation.SyntaxTrees.Single();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Semantics;
......@@ -16,7 +18,9 @@ public class AnalysisContextInfoTests
public void InitializeTest()
{
var code = @"class C { void M() { return; } }";
var compilation = CreateCompilation(code);
var parseOptions = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None)
.WithFeatures(new[] { new KeyValuePair<string, string>("IOperation", "true") });
var compilation = CreateCompilation(code, parseOptions: parseOptions);
Verify(compilation, nameof(AnalysisContext.RegisterCodeBlockAction));
Verify(compilation, nameof(AnalysisContext.RegisterCodeBlockStartAction));
......@@ -93,12 +97,12 @@ private static DiagnosticDescriptor GetRule(string id)
isEnabledByDefault: true);
}
private static Compilation CreateCompilation(string source)
private static Compilation CreateCompilation(string source, CSharpParseOptions parseOptions = null)
{
string fileName = "Test.cs";
string projectName = "TestProject";
var syntaxTree = CSharpSyntaxTree.ParseText(source, path: fileName);
var syntaxTree = CSharpSyntaxTree.ParseText(source, path: fileName, options: parseOptions);
return CSharpCompilation.Create(
projectName,
......
......@@ -2097,4 +2097,110 @@ public sealed override void Initialize(AnalysisContext context)
OperationKind.LiteralExpression);
}
}
// This analyzer is to test operation action registration method in AnalysisContext
public class IOperationFeatureFlagTestAnalyzer1 : DiagnosticAnalyzer
{
private const string ReliabilityCategory = "Reliability";
public static readonly DiagnosticDescriptor OperationActionDescriptor = new DiagnosticDescriptor(
"OperationAction1",
"An operation related action is invoked",
"An {0} action is invoked in {1} context.",
ReliabilityCategory,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(OperationActionDescriptor);
public sealed override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction(
(operationContext) =>
{
operationContext.ReportDiagnostic(
Diagnostic.Create(OperationActionDescriptor, operationContext.Operation.Syntax.GetLocation(), "Operation", "Analysis"));
},
OperationKind.LiteralExpression);
}
}
// This analyzer is to test operation action registration method in CompilationStartAnalysisContext
public class IOperationFeatureFlagTestAnalyzer2 : DiagnosticAnalyzer
{
private const string ReliabilityCategory = "Reliability";
public static readonly DiagnosticDescriptor OperationActionDescriptor = new DiagnosticDescriptor(
"OperationAction2",
"An operation related action is invoked",
"An {0} action is invoked in {1} context.",
ReliabilityCategory,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(OperationActionDescriptor);
public sealed override void Initialize(AnalysisContext context)
{
context.RegisterCompilationStartAction(
(compilationStartContext) =>
{
compilationStartContext.RegisterOperationAction(
(operationContext) =>
{
operationContext.ReportDiagnostic(
Diagnostic.Create(OperationActionDescriptor, operationContext.Operation.Syntax.GetLocation(), "Operation", "CompilationStart within Analysis"));
},
OperationKind.LiteralExpression);
});
}
}
// This analyzer is to test GetOperation method in SemanticModel
public class IOperationFeatureFlagTestAnalyzer3 : DiagnosticAnalyzer
{
private const string ReliabilityCategory = "Reliability";
public static readonly DiagnosticDescriptor GetOperationDescriptor = new DiagnosticDescriptor(
"GetOperation",
"An IOperation is returned by SemanticModel",
"An IOperation is returned by SemanticModel.",
ReliabilityCategory,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(GetOperationDescriptor);
public sealed override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(syntaxContext) =>
{
var node = syntaxContext.Node;
var model = syntaxContext.SemanticModel;
if (model.GetOperation(node) != null)
{
syntaxContext.ReportDiagnostic(Diagnostic.Create(GetOperationDescriptor, node.GetLocation()));
}
},
Microsoft.CodeAnalysis.CSharp.SyntaxKind.NumericLiteralExpression);
context.RegisterSyntaxNodeAction(
(syntaxContext) =>
{
var node = syntaxContext.Node;
var model = syntaxContext.SemanticModel;
if (model.GetOperation(node) != null)
{
syntaxContext.ReportDiagnostic(Diagnostic.Create(GetOperationDescriptor, node.GetLocation()));
}
},
Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.NumericLiteralExpression);
}
}
}
\ No newline at end of file
......@@ -712,6 +712,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Feature &apos;IOperation&apos; is disabled..
/// </summary>
internal static string IOperationFeatureDisabled {
get {
return ResourceManager.GetString("IOperationFeatureDisabled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Argument to &apos;/keepalive&apos; option is not a 32-bit integer..
/// </summary>
......@@ -1073,7 +1082,7 @@ internal class CodeAnalysisResources {
}
/// <summary>
/// Looks up a localized string similar to Then span does not include the end of a line..
/// Looks up a localized string similar to The span does not include the end of a line..
/// </summary>
internal static string SpanDoesNotIncludeEndOfLine {
get {
......
......@@ -510,4 +510,7 @@
<value>Exception occurred with following context:
{0}</value>
</data>
<data name="IOperationFeatureDisabled" xml:space="preserve">
<value>Feature 'IOperation' is disabled.</value>
</data>
</root>
\ No newline at end of file
......@@ -2205,5 +2205,7 @@ internal bool IsTypeMissing(WellKnownType type)
{
return _lazyMakeWellKnownTypeMissingMap != null && _lazyMakeWellKnownTypeMissingMap.ContainsKey((int)type);
}
internal abstract bool IsIOperationFeatureEnabled();
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
......@@ -71,7 +72,19 @@ public SyntaxTree SyntaxTree
/// <returns></returns>
public IOperation GetOperation(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return this.GetOperationCore(node, cancellationToken);
if (this.Compilation.IsIOperationFeatureEnabled())
{
try
{
return GetOperationCore(node, cancellationToken);
}
catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
{
// Log a Non-fatal-watson and then ignore the crash in the attempt of getting operation
}
return null;
}
throw new InvalidOperationException(CodeAnalysisResources.IOperationFeatureDisabled);
}
protected abstract IOperation GetOperationCore(SyntaxNode node, CancellationToken cancellationToken);
......
......@@ -1384,7 +1384,7 @@ private bool ShouldExecuteOperationBlockActions(AnalysisScope analysisScope, ISy
var symbol = symbolEvent.Symbol;
var executeSyntaxNodeActions = ShouldExecuteSyntaxNodeActions(analysisScope);
var executeCodeBlockActions = ShouldExecuteCodeBlockActions(analysisScope, symbol);
var executeOperationActions = ShouldExecuteOperationActions(analysisScope);
var executeOperationActions = this.analyzerExecutor.Compilation.IsIOperationFeatureEnabled() && ShouldExecuteOperationActions(analysisScope);
var executeOperationBlockActions = ShouldExecuteOperationBlockActions(analysisScope, symbol);
if (executeSyntaxNodeActions || executeOperationActions || executeCodeBlockActions || executeOperationBlockActions)
......
......@@ -200,7 +200,7 @@ public void ExecuteInitializeMethod(DiagnosticAnalyzer analyzer, HostSessionStar
{
// The Initialize method should be run asynchronously in case it is not well behaved, e.g. does not terminate.
ExecuteAndCatchIfThrows(analyzer,
() => analyzer.Initialize(new AnalyzerAnalysisContext(analyzer, sessionScope)));
() => analyzer.Initialize(new AnalyzerAnalysisContext(analyzer, sessionScope, _compilation.IsIOperationFeatureEnabled())));
}
/// <summary>
......
......@@ -70,6 +70,14 @@ internal static void VerifyDiagnosticLocationsInCompilation(Diagnostic diagnosti
}
}
}
internal static void VerifyIOperationFeatureFlag(bool isIOperationFeatureEnabled)
{
if (!isIOperationFeatureEnabled)
{
throw new InvalidOperationException(CodeAnalysisResources.IOperationFeatureDisabled);
}
}
private static void VerifyDiagnosticLocationInCompilation(string id, Location location, Compilation compilation)
{
......
......@@ -17,11 +17,14 @@ internal sealed class AnalyzerAnalysisContext : AnalysisContext
{
private readonly DiagnosticAnalyzer _analyzer;
private readonly HostSessionStartAnalysisScope _scope;
private readonly bool _isIOperationFeatureEnabled;
public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope scope)
public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope scope, bool isIOperationFeatureEnabled = false)
{
_analyzer = analyzer;
_scope = scope;
_isIOperationFeatureEnabled = isIOperationFeatureEnabled;
}
public override void RegisterCompilationStartAction(Action<CompilationStartAnalysisContext> action)
......@@ -74,18 +77,21 @@ public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNo
public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds);
_scope.RegisterOperationAction(_analyzer, action, operationKinds);
}
public override void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
DiagnosticAnalysisContextHelpers.VerifyArguments(action);
_scope.RegisterOperationBlockStartAction(_analyzer, action);
}
public override void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
DiagnosticAnalysisContextHelpers.VerifyArguments(action);
_scope.RegisterOperationBlockAction(_analyzer, action);
}
......@@ -109,6 +115,8 @@ internal sealed class AnalyzerCompilationStartAnalysisContext : CompilationStart
private readonly DiagnosticAnalyzer _analyzer;
private readonly HostCompilationStartAnalysisScope _scope;
private readonly CompilationAnalysisValueProviderFactory _compilationAnalysisValueProviderFactory;
private readonly bool _isIOperationFeatureEnabled;
public AnalyzerCompilationStartAnalysisContext(
DiagnosticAnalyzer analyzer,
......@@ -122,6 +130,7 @@ internal sealed class AnalyzerCompilationStartAnalysisContext : CompilationStart
_analyzer = analyzer;
_scope = scope;
_compilationAnalysisValueProviderFactory = compilationAnalysisValueProviderFactory;
_isIOperationFeatureEnabled = compilation.IsIOperationFeatureEnabled();
}
public override void RegisterCompilationEndAction(Action<CompilationAnalysisContext> action)
......@@ -161,17 +170,20 @@ public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNo
public override void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
_scope.RegisterOperationBlockStartAction(_analyzer, action);
}
public override void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
DiagnosticAnalysisContextHelpers.VerifyArguments(action);
_scope.RegisterOperationBlockAction(_analyzer, action);
}
public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
{
DiagnosticAnalysisContextHelpers.VerifyIOperationFeatureFlag(_isIOperationFeatureEnabled);
_scope.RegisterOperationAction(_analyzer, action, operationKinds);
}
......
......@@ -13,6 +13,8 @@ public static class TestOptions
public static readonly CSharpParseOptions Script = new CSharpParseOptions(kind: SourceCodeKind.Script, documentationMode: DocumentationMode.None);
public static readonly CSharpParseOptions Regular = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None);
public static readonly CSharpParseOptions RegularWithDocumentationComments = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Diagnose);
public static readonly CSharpParseOptions RegularWithIOperationFeature = Regular.WithIOperationsFeature();
private static readonly SmallDictionary<string, string> s_experimentalFeatures = new SmallDictionary<string, string>(); // no experimental features to enable
public static readonly CSharpParseOptions ExperimentalParseOptions =
......@@ -53,5 +55,10 @@ public static CSharpParseOptions WithStrictFeature(this CSharpParseOptions optio
{
return options.WithFeature("strict", "true");
}
public static CSharpParseOptions WithIOperationsFeature(this CSharpParseOptions options)
{
return options.WithFeature("IOperation", "true");
}
}
}
......@@ -6,6 +6,8 @@ Public Class TestOptions
Public Shared ReadOnly Script As New VisualBasicParseOptions(kind:=SourceCodeKind.Script)
Public Shared ReadOnly Regular As New VisualBasicParseOptions(kind:=SourceCodeKind.Regular)
Public Shared ReadOnly RegularWithIOperationFeature As VisualBasicParseOptions = Regular.WithIOperationFeature()
Public Shared ReadOnly ReleaseDll As VisualBasicCompilationOptions = New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel:=OptimizationLevel.Release).WithExtendedCustomDebugInformation(True)
Public Shared ReadOnly ReleaseExe As VisualBasicCompilationOptions = New VisualBasicCompilationOptions(OutputKind.ConsoleApplication, optimizationLevel:=OptimizationLevel.Release).WithExtendedCustomDebugInformation(True)
......@@ -45,4 +47,9 @@ Friend Module TestOptionExtensions
Public Function WithDeterministicFeature(options As VisualBasicParseOptions) As VisualBasicParseOptions
Return options.WithFeature("Deterministic", "true")
End Function
<Extension()>
Public Function WithIOperationFeature(options As VisualBasicParseOptions) As VisualBasicParseOptions
Return options.WithFeature("IOperation", "true")
End Function
End Module
......@@ -2652,6 +2652,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return New SymbolSearcher(Me).GetSymbolsWithName(predicate, filter, cancellationToken)
End Function
Friend Overrides Function IsIOperationFeatureEnabled() As Boolean
Dim options = DirectCast(Me.SyntaxTrees.First().Options, VisualBasicParseOptions)
Dim IOperationFeatureFlag = InternalSyntax.FeatureExtensions.GetFeatureFlag(InternalSyntax.Feature.IOperation)
If IOperationFeatureFlag IsNot Nothing Then
Return options.Features.ContainsKey(IOperationFeatureFlag)
End If
Return False
End Function
#End Region
Private Class SymbolSearcher
......
......@@ -1951,5 +1951,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
FEATURE_PartialModules
FEATURE_PartialInterfaces
FEATURE_ImplementingReadonlyOrWriteonlyPropertyWithReadwrite
FEATURE_IOperation
End Enum
End Namespace
......@@ -29,12 +29,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
PartialModules
PartialInterfaces
ImplementingReadonlyOrWriteonlyPropertyWithReadwrite
IOperation
End Enum
Friend Module FeatureExtensions
<Extension>
Friend Function GetFeatureFlag(feature As Feature) As String
Select Case feature
Case Feature.IOperation
Return "IOperation"
Case Else
Return Nothing
......@@ -130,6 +133,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Return ERRID.FEATURE_PartialInterfaces
Case Feature.ImplementingReadonlyOrWriteonlyPropertyWithReadwrite
Return ERRID.FEATURE_ImplementingReadonlyOrWriteonlyPropertyWithReadwrite
Case Feature.IOperation
Return ERRID.FEATURE_IOperation
Case Else
Throw ExceptionUtilities.UnexpectedValue(feature)
End Select
......
......@@ -50,7 +50,7 @@ End Module
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source)
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim nodes = tree.GetRoot().DescendantNodes().OfType(Of AssignmentStatementSyntax).ToArray()
......@@ -140,7 +140,7 @@ End Module
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source)
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim nodes = tree.GetRoot().DescendantNodes().OfType(Of AssignmentStatementSyntax).ToArray()
......
......@@ -30,6 +30,7 @@ public partial class TestWorkspace
private const string ReportDiagnosticAttributeName = "ReportDiagnostic";
private const string ParseOptionsElementName = "ParseOptions";
private const string LanguageVersionAttributeName = "LanguageVersion";
private const string FeaturesAttributeName = "Features";
private const string DocumentationModeAttributeName = "DocumentationMode";
private const string DocumentElementName = "Document";
private const string AnalyzerElementName = "Analyzer";
......
......@@ -350,6 +350,12 @@ private static ParseOptions GetParseOptionsWorker(XElement projectElement, strin
parseOptions = parseOptions.WithDocumentationMode(documentationMode.Value);
}
var featuresAttribute = projectElement.Attribute(FeaturesAttributeName);
if (featuresAttribute != null)
{
parseOptions = parseOptions.WithFeatures(featuresAttribute.Value.Split(',').Select(f => KeyValuePair.Create(f, "true")));
}
return parseOptions;
}
......
......@@ -414,7 +414,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
<WpfFact, WorkItem(937956, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/937956"), Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub TestDiagnosticAnalyzerExceptionHandledGracefully()
Dim test = <Workspace>
<Project Language="C#" CommonReferences="true">
<Project Language="C#" CommonReferences="true" Features="IOperation">
<Document FilePath="Test.cs">
class Foo { }
</Document>
......@@ -515,7 +515,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
<WpfFact, WorkItem(937939, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/937939"), Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub TestOperationAnalyzers()
Dim test = <Workspace>
<Project Language="C#" CommonReferences="true">
<Project Language="C#" CommonReferences="true" Features="IOperation">
<Document FilePath="Test.cs">
class Foo { void M() { int x = 0; } }
</Document>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册