提交 dc1afdf9 编写于 作者: D Daniel Plaisted

Remove disabled compilation error telemetry code

上级 cd68b0de
......@@ -133,9 +133,6 @@
<Compile Include="Options\NamingStylesOptionPage.cs" />
<Compile Include="Options\AdvancedOptionPageStrings.cs" />
<Compile Include="Options\IntelliSenseOptionPageStrings.cs" />
<Compile Include="Telemetry\CompilationErrorDetailDiscoverer.cs" />
<Compile Include="Telemetry\CompilationErrorDetails.cs" />
<Compile Include="Telemetry\CSharpCompilationErrorTelemetryIncrementalAnalyzer.cs" />
<Compile Include="Venus\CSharpAdditionalFormattingRuleLanguageService.cs" />
<Compile Include="CSharpPackage.cs" />
<Compile Include="CSharpVSResources.Designer.cs">
......
// 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.Composition;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.Internal.VisualStudio.Shell;
using Microsoft.VisualStudio.LanguageServices.Implementation.CompilationErrorTelemetry;
using Roslyn.Utilities;
using System.Security.Cryptography;
namespace Microsoft.VisualStudio.LanguageServices.Telemetry
{
[ExportPerLanguageIncrementalAnalyzerProvider(CompilationErrorTelemetryIncrementalAnalyzer.Name, LanguageNames.CSharp), Shared]
internal class CSharpCompilationErrorTelemetryIncrementalAnalyzer : IPerLanguageIncrementalAnalyzerProvider
{
public IIncrementalAnalyzer CreatePerLanguageIncrementalAnalyzer(Workspace workspace, IIncrementalAnalyzerProvider provider)
{
return new Analyzer();
}
private class Analyzer : IIncrementalAnalyzer
{
private const string EventPrefix = "VS/Compilers/Compilation/";
private const string PropertyPrefix = "VS.Compilers.Compilation.Error.";
private const string TelemetryEventPath = EventPrefix + "Error";
private const string TelemetryExceptionEventPath = EventPrefix + "TelemetryUnhandledException";
private const string TelemetryErrorId = PropertyPrefix + "ErrorId";
private const string TelemetryMethodName = PropertyPrefix + "MethodName";
private const string TelemetryUnresolvedMemberName = PropertyPrefix + "UnresolvedMemberName";
private const string TelemetryLeftExpressionDocId = PropertyPrefix + "LeftExpressionDocId";
private const string TelemetryBaseTypes = PropertyPrefix + "LeftExpressionBaseTypeDocIds";
private const string TelemetryGenericArguments = PropertyPrefix + "GenericArgumentDocIds";
private const string TelemetryProjectGuid = PropertyPrefix + "ProjectGuid";
private const string TelemetryMismatchedArgumentTypeDocIds = PropertyPrefix + "MismatchedArgumentDocIds";
private const string UnspecifiedProjectGuid = "unspecified";
private SolutionId _currentSolutionId;
private readonly CompilationErrorDetailDiscoverer _errorDetailDiscoverer = new CompilationErrorDetailDiscoverer();
private readonly ProjectGuidCache _projectGuidCache = new ProjectGuidCache();
private readonly CompilationErrorDetailCache _errorDetailCache = new CompilationErrorDetailCache();
public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken)
{
try
{
// do nothing if this document is not currently open.
// to prevent perf from getting too poor for large projects, only examine open documents.
if (!document.IsOpen())
{
return;
}
// Only analyzing C# for now
if (document.Project.Language != LanguageNames.CSharp)
{
return;
}
List<CompilationErrorDetails> errorDetails = await _errorDetailDiscoverer.GetCompilationErrorDetails(document, bodyOpt, cancellationToken).ConfigureAwait(false);
var errorsToReport = _errorDetailCache.GetErrorsToReportAndRecordErrors(document.Id, errorDetails);
if (errorsToReport != null)
{
using (var hashProvider = new SHA256CryptoServiceProvider())
{
foreach (CompilationErrorDetails errorDetail in errorsToReport)
{
var telemetryEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryEventPath);
telemetryEvent.SetStringProperty(TelemetryErrorId, errorDetail.ErrorId);
string projectGuid = _projectGuidCache.GetProjectGuidFromProjectPath(document.Project.FilePath);
telemetryEvent.SetStringProperty(TelemetryProjectGuid, string.IsNullOrEmpty(projectGuid) ? UnspecifiedProjectGuid : projectGuid.ToString());
if (!string.IsNullOrEmpty(errorDetail.UnresolvedMemberName))
{
telemetryEvent.SetStringProperty(TelemetryUnresolvedMemberName, GetHashedString(errorDetail.UnresolvedMemberName, hashProvider));
}
if (!string.IsNullOrEmpty(errorDetail.LeftExpressionDocId))
{
telemetryEvent.SetStringProperty(TelemetryLeftExpressionDocId, GetHashedString(errorDetail.LeftExpressionDocId, hashProvider));
}
if (!IsArrayNullOrEmpty(errorDetail.LeftExpressionBaseTypeDocIds))
{
string telemetryBaseTypes = string.Join(";", errorDetail.LeftExpressionBaseTypeDocIds.Select(docId => GetHashedString(docId, hashProvider)));
telemetryEvent.SetStringProperty(TelemetryBaseTypes, telemetryBaseTypes);
}
if (!IsArrayNullOrEmpty(errorDetail.GenericArguments))
{
string telemetryGenericArguments = string.Join(";", errorDetail.GenericArguments.Select(docId => GetHashedString(docId, hashProvider)));
telemetryEvent.SetStringProperty(TelemetryGenericArguments, telemetryGenericArguments);
}
if (!string.IsNullOrEmpty(errorDetail.MethodName))
{
telemetryEvent.SetStringProperty(TelemetryMethodName, GetHashedString(errorDetail.MethodName, hashProvider));
}
if (!IsArrayNullOrEmpty(errorDetail.ArgumentTypes))
{
string telemetryMisMatchedArgumentTypeDocIds = string.Join(";", errorDetail.ArgumentTypes.Select(docId => GetHashedString(docId, hashProvider)));
telemetryEvent.SetStringProperty(TelemetryMismatchedArgumentTypeDocIds, telemetryMisMatchedArgumentTypeDocIds);
}
TelemetryHelper.DefaultTelemetrySession.PostEvent(telemetryEvent);
}
}
}
}
catch (Exception e)
{
// The telemetry service itself can throw.
// So, to be very careful, put this in a try/catch too.
try
{
var exceptionEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryExceptionEventPath);
exceptionEvent.SetStringProperty("Type", e.GetTypeDisplayName());
exceptionEvent.SetStringProperty("Message", e.Message);
exceptionEvent.SetStringProperty("StackTrace", e.StackTrace);
TelemetryHelper.DefaultTelemetrySession.PostEvent(exceptionEvent);
}
catch
{
}
}
}
public Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyTask;
}
public Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyTask;
}
public Task DocumentOpenAsync(Document document, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyTask;
}
public Task DocumentCloseAsync(Document document, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyTask;
}
public Task DocumentResetAsync(Document document, CancellationToken cancellationToken)
{
_errorDetailCache.ClearCacheForDocument(document.Id);
return SpecializedTasks.EmptyTask;
}
public bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e)
{
return false;
}
public Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancellationToken)
{
if (solution.Id != _currentSolutionId)
{
_projectGuidCache.Clear();
_errorDetailCache.Clear();
_currentSolutionId = solution.Id;
}
return SpecializedTasks.EmptyTask;
}
public void RemoveDocument(DocumentId documentId)
{
_errorDetailCache.ClearCacheForDocument(documentId);
}
public void RemoveProject(ProjectId projectId)
{
}
private static string GetHashedString(string unhashedString, SHA256 hashProvider)
{
// The point of hashing here is to obscure customer data.
// So, if we get any empty values (noone knows why this happens for certain... has only been observed in dumps)
// an empty string is fine. It will appear as an extra semicolon in the MD value.
if (string.IsNullOrEmpty(unhashedString))
{
return string.Empty;
}
if (TelemetryHelper.DefaultTelemetrySession.CanCollectPrivateInformation())
{
return unhashedString;
}
byte[] theHash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(unhashedString));
StringBuilder sb = new StringBuilder(theHash.Length);
for (int i = 0; i < theHash.Length; i++)
{
sb.AppendFormat("{0:X}", theHash[i]);
}
return sb.ToString();
}
private static bool IsArrayNullOrEmpty(Array list)
{
return (list == null) || (list.Length == 0);
}
}
private class CompilationErrorDetailCache
{
private readonly Dictionary<DocumentId, HashSet<CompilationErrorDetails>> _errorCache = new Dictionary<DocumentId, HashSet<CompilationErrorDetails>>();
private readonly object _lockObject = new object();
public IEnumerable<CompilationErrorDetails> GetErrorsToReportAndRecordErrors(DocumentId documentId, IEnumerable<CompilationErrorDetails> errors)
{
if (errors == null)
{
return Enumerable.Empty<CompilationErrorDetails>();
}
lock (_lockObject)
{
List<CompilationErrorDetails> ret = null;
if (!_errorCache.TryGetValue(documentId, out var cachedErrorsForDocument))
{
cachedErrorsForDocument = new HashSet<CompilationErrorDetails>();
_errorCache[documentId] = cachedErrorsForDocument;
}
foreach (var error in errors)
{
if (!cachedErrorsForDocument.Contains(error))
{
ret = ret ?? new List<CompilationErrorDetails>();
ret.Add(error);
}
}
// Only add errors to the cache after looping through the whole list. This is so that if there are multiple instances of the same error
// (with all the same data that we gather) in a document, that it willget reported multiple
if (ret != null)
{
foreach (var error in ret)
{
cachedErrorsForDocument.Add(error);
}
}
return ret;
}
}
public void ClearCacheForDocument(DocumentId documentId)
{
lock (_lockObject)
{
_errorCache.Remove(documentId);
}
}
public void Clear()
{
lock (_lockObject)
{
_errorCache.Clear();
}
}
}
private class ProjectGuidCache
{
private readonly Dictionary<string, string> _projectGuids = new Dictionary<string, string>();
private readonly object _lockObject = new object();
public void Clear()
{
lock (_lockObject)
{
_projectGuids.Clear();
}
}
public string GetProjectGuidFromProjectPath(string projectPath)
{
// misc project, web site and etc might not have project path.
if (string.IsNullOrEmpty(projectPath))
{
return null;
}
lock (_lockObject)
{
if (_projectGuids.TryGetValue(projectPath, out var ret))
{
return ret;
}
try
{
XDocument project = XDocument.Load(projectPath);
ret = (from xElement in project.Descendants()
where xElement.Name.LocalName.Equals("ProjectGuid", StringComparison.InvariantCultureIgnoreCase) &&
xElement.Parent != null &&
xElement.Parent.Name.LocalName.Equals("PropertyGroup", StringComparison.InvariantCultureIgnoreCase)
select xElement.Value).FirstOrDefault();
if (ret != null)
{
_projectGuids[projectPath] = ret;
return ret;
}
}
catch
{
}
return null;
}
}
}
}
}
// 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 System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Telemetry
{
internal class CompilationErrorDetailDiscoverer
{
/// <summary>
/// name does not exist in context
/// </summary>
private const string CS0103 = "CS0103";
/// <summary>
/// type or namespace could not be found
/// </summary>
private const string CS0246 = "CS0246";
/// <summary>
/// wrong number of type args
/// </summary>
private const string CS0305 = "CS0305";
/// <summary>
/// The non-generic type 'A' cannot be used with type arguments
/// </summary>
private const string CS0308 = "CS0308";
/// <summary>
/// An attempt was made to use a non-attribute class in an attribute block. All the attribute types need to be inherited from System.Attribute
/// </summary>
private const string CS0616 = "CS0616";
/// <summary>
/// type does not contain a definition of method or extension method
/// </summary>
private const string CS1061 = "CS1061";
/// <summary>
/// The type of one argument in a method does not match the type that was passed when the class was instantiated. This error typically appears along with CS1502
/// Likely to occur when a type / member exists in a new framework but its specific overload is missing.
/// </summary>
private const string CS1503 = "CS1503";
/// <summary>
/// cannot find implementation of query pattern
/// </summary>
private const string CS1935 = "CS1935";
/// <summary>
/// Used to record generic argument types the semantic model doesn't know about
/// </summary>
private const string UnknownGenericArgumentTypeName = "Unknown";
/// <summary>
/// Used to record symbol names for error scenarios where GetSymbolInfo/GetTypeInfo returns no symbol.
/// </summary>
private const string UnknownSymbolName = "Unknown";
public async Task<List<CompilationErrorDetails>> GetCompilationErrorDetails(Document document, SyntaxNode bodyOpt, CancellationToken cancellationToken)
{
try
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
ImmutableArray<Diagnostic> diagnostics;
// If we have the SyntaxNode bodyOpt,
// then we can use its fullSpan property to process a subset of the document.
if (bodyOpt == null)
{
diagnostics = semanticModel.GetDiagnostics(cancellationToken: cancellationToken);
}
else
{
diagnostics = semanticModel.GetDiagnostics(bodyOpt.FullSpan, cancellationToken: cancellationToken);
}
if (diagnostics.Length == 0)
{
return null;
}
var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
List<CompilationErrorDetails> ret = new List<CompilationErrorDetails>();
foreach (var diagnostic in diagnostics)
{
if (diagnostic.Severity != DiagnosticSeverity.Error || diagnostic.IsWarningAsError)
{
continue;
}
if (!IsTrackedCompilationError(diagnostic))
{
continue;
}
string errorDetailsFilename = diagnostic.Location.GetLineSpan().Path;
string errorDetailsUnresolvedMemberName = null;
string errorDetailsMethodName = null;
string errorDetailsLeftExpressionDocId = null;
string[] errorDetailsGenericArguments = null;
string[] errorDetailsArgumentTypes = null;
string[] errorDetailsLeftExpressionBaseTypeDocIds = null;
TextSpan span = diagnostic.Location.SourceSpan;
var node = root.FindNode(span);
if (node == null)
{
continue;
}
// If the expression binds, this could just be an extension method so we will continue and not
// log, as it's not actually an error.
if (ExpressionBinds(node, semanticModel, cancellationToken, checkForExtensionMethods: true))
{
continue;
}
// This is used to get unresolved member names. It will not alway find a member name, but has been tested to do so
// in the cases where the error code needs it.
syntaxFacts.GetNameAndArityOfSimpleName(node, out var name, out var arity);
errorDetailsUnresolvedMemberName = name;
// Here we reuse the unresolved member name field for attribute classes that can't be resolved as
// actually being attributes. Could factor this into a separate field for readability later.
AttributeSyntax attributeSyntax = node as AttributeSyntax;
if (attributeSyntax != null)
{
errorDetailsUnresolvedMemberName = semanticModel.GetTypeInfo(attributeSyntax, cancellationToken).Type.GetDocumentationCommentId();
}
GenericNameSyntax genericNameSyntax = node as GenericNameSyntax;
if (genericNameSyntax != null)
{
List<string> genericArgumentDocIds = new List<string>();
foreach (var genericArgument in genericNameSyntax.TypeArgumentList.Arguments)
{
var semanticInfo = semanticModel.GetTypeInfo(genericArgument, cancellationToken);
if (semanticInfo.Type != null)
{
genericArgumentDocIds.Add(GetDocId(semanticInfo.Type));
}
else
{
genericArgumentDocIds.Add(UnknownGenericArgumentTypeName);
}
}
errorDetailsGenericArguments = genericArgumentDocIds.ToArray();
}
ArgumentSyntax argumentSyntax = node as ArgumentSyntax;
if (argumentSyntax != null)
{
var argumentListSyntax = argumentSyntax.GetAncestor<BaseArgumentListSyntax>().Arguments;
var invocationExpression = argumentSyntax.GetAncestor<InvocationExpressionSyntax>();
errorDetailsArgumentTypes = (from argument in argumentListSyntax
select GetDocId(semanticModel.GetTypeInfo(argument.Expression, cancellationToken).Type)).ToArray();
if (invocationExpression != null)
{
var memberAccessExpression = invocationExpression.Expression as ExpressionSyntax;
var symbolInfo = semanticModel.GetSymbolInfo(memberAccessExpression, cancellationToken);
if (symbolInfo.CandidateSymbols.Length > 0)
{
// In this case, there is argument mismatch of some sort.
// Here we are getting the method name of any candidate symbols, then
// getting the docid of the type where the argument mismatch happened and storing this in LeftExpressionDocId.
errorDetailsMethodName = symbolInfo.CandidateSymbols.First().Name;
errorDetailsLeftExpressionDocId = GetDocId(symbolInfo.CandidateSymbols.First().ContainingType);
}
}
}
if (syntaxFacts.IsSimpleMemberAccessExpression(node.Parent))
{
var expression = node.Parent;
var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression);
if (leftExpression != null)
{
var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken);
var leftExpressionType = semanticInfo.Type;
if (leftExpressionType != null)
{
errorDetailsLeftExpressionDocId = GetDocId(leftExpressionType);
IEnumerable<string> baseTypeDocids = leftExpressionType.GetBaseTypes().Select(t => GetDocId(t));
errorDetailsLeftExpressionBaseTypeDocIds = baseTypeDocids.ToArray();
}
}
}
ret.Add(new CompilationErrorDetails(diagnostic.Id, errorDetailsFilename, errorDetailsMethodName, errorDetailsUnresolvedMemberName,
errorDetailsLeftExpressionDocId, errorDetailsLeftExpressionBaseTypeDocIds, errorDetailsGenericArguments, errorDetailsArgumentTypes));
}
return ret;
}
catch (Exception e)
{
List<CompilationErrorDetails> ret = new List<CompilationErrorDetails>();
ret.Add(new CompilationErrorDetails("EXCEPTION", e.Message, e.StackTrace, null, null, null, null, null));
return ret;
}
}
private string GetDocId(ISymbol symbol)
{
if (symbol == null)
{
return UnknownSymbolName;
}
if (symbol is INamedTypeSymbol)
{
var typeSymbol = (INamedTypeSymbol)symbol;
if (typeSymbol.IsGenericType && typeSymbol.OriginalDefinition != null)
{
return typeSymbol.OriginalDefinition.GetDocumentationCommentId();
}
}
else if (symbol is IMethodSymbol)
{
var methodSymbol = (IMethodSymbol)symbol;
if (methodSymbol.IsGenericMethod && methodSymbol.OriginalDefinition != null)
{
return methodSymbol.OriginalDefinition.GetDocumentationCommentId();
}
}
return symbol.GetDocumentationCommentId();
}
private bool IsTrackedCompilationError(Diagnostic diagnostic)
{
return diagnostic.Id == CS0103 ||
diagnostic.Id == CS0246 ||
diagnostic.Id == CS0305 ||
diagnostic.Id == CS0308 ||
diagnostic.Id == CS0616 ||
diagnostic.Id == CS1061 ||
diagnostic.Id == CS1503 ||
diagnostic.Id == CS1935;
}
private bool ExpressionBinds(SyntaxNode expression, SemanticModel semanticModel, CancellationToken cancellationToken, bool checkForExtensionMethods = false)
{
// See if the name binds to something other then the error type. If it does, there's nothing further we need to do.
// For extension methods, however, we will continue to search if there exists any better matched method.
cancellationToken.ThrowIfCancellationRequested();
var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
if (symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure && !checkForExtensionMethods)
{
return true;
}
return symbolInfo.Symbol != null;
}
}
}
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Internal.VisualStudio.Shell;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Telemetry
{
internal struct CompilationErrorDetails : IEquatable<CompilationErrorDetails>
{
public CompilationErrorDetails(string errorId, string fileName, string methodName, string unresolvedMemberName,
string leftExpressionDocId, string[] leftExpressionBaseTypeDocIds, string[] genericArguments, string[] argumentTypes)
{
ErrorId = errorId;
Filename = fileName;
MethodName = methodName;
UnresolvedMemberName = unresolvedMemberName;
LeftExpressionDocId = leftExpressionDocId;
LeftExpressionBaseTypeDocIds = leftExpressionBaseTypeDocIds;
GenericArguments = genericArguments;
ArgumentTypes = argumentTypes;
_hashCode = null;
}
public readonly string Filename;
public readonly string ErrorId;
public readonly string MethodName;
public readonly string UnresolvedMemberName;
public readonly string LeftExpressionDocId;
public readonly string[] LeftExpressionBaseTypeDocIds;
public readonly string[] GenericArguments;
public readonly string[] ArgumentTypes;
private int? _hashCode;
public override int GetHashCode()
{
if (_hashCode.HasValue)
{
return _hashCode.Value;
}
_hashCode = Hash.Combine(Filename,
Hash.Combine(ErrorId,
Hash.Combine(MethodName,
Hash.Combine(UnresolvedMemberName,
Hash.Combine(LeftExpressionDocId,
Hash.CombineValues(LeftExpressionBaseTypeDocIds,
Hash.CombineValues(GenericArguments,
Hash.CombineValues(ArgumentTypes, 0))))))));
return _hashCode.Value;
}
public override bool Equals(object obj)
{
if (obj is CompilationErrorDetails)
{
return Equals((CompilationErrorDetails)obj);
}
return base.Equals(obj);
}
public bool Equals(CompilationErrorDetails other)
{
// Avoid string comparisons unless the hashcodes match
if (GetHashCode() != other.GetHashCode())
{
return false;
}
return Filename == other.Filename &&
ErrorId == other.ErrorId &&
MethodName == other.MethodName &&
UnresolvedMemberName == other.UnresolvedMemberName &&
LeftExpressionDocId == other.LeftExpressionDocId &&
SameStringArray(LeftExpressionBaseTypeDocIds, other.LeftExpressionBaseTypeDocIds) &&
SameStringArray(GenericArguments, other.GenericArguments) &&
SameStringArray(ArgumentTypes, other.ArgumentTypes);
}
private static bool SameStringArray(string[] stringArray1, string[] stringArray2)
{
if (stringArray1 == null && stringArray2 == null)
{
return true;
}
else if (stringArray1 == null || stringArray2 == null)
{
return false;
}
if (stringArray1.Length != stringArray2.Length)
{
return false;
}
for (int i = 0; i < stringArray1.Length; i++)
{
if (stringArray1[i] != stringArray2[i])
{
return false;
}
}
return true;
}
}
}
// 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.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.SolutionCrawler;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CompilationErrorTelemetry
{
// Disabled compilation error telemetry per discussion with .net team.
// tracking bug - https://github.com/dotnet/roslyn/issues/11133
// [ExportIncrementalAnalyzerProvider(WorkspaceKind.Host), Shared]
internal class CompilationErrorTelemetryIncrementalAnalyzer : IncrementalAnalyzerProviderBase
{
public const string Name = "CompilationErrorTelemetryIncrementalAnalyzer";
[ImportingConstructor]
public CompilationErrorTelemetryIncrementalAnalyzer(
[ImportMany] IEnumerable<Lazy<IPerLanguageIncrementalAnalyzerProvider, PerLanguageIncrementalAnalyzerProviderMetadata>> perLanguageProviders) :
base(Name, perLanguageProviders)
{
}
}
}
......@@ -57,7 +57,6 @@
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyIdentityList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNameList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNamePrefixList.cs" />
<Compile Include="Implementation\CompilationErrorTelemetry\CompilationErrorTelemetryIncrementalAnalyzer.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioVenusSpanMappingService.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioWorkspaceDiagnosticAnalyzerProviderService.AnalyzerAssemblyLoader.cs" />
<Compile Include="Implementation\EditAndContinue\Interop\NativeMethods.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册