private void ShowInfoBarIfNecessary() { // Only check for whether we should show an info bar once per session. _infoBarChecked = true; if (_experimentationService.IsExperimentEnabled(AnalyzerEnabledFlight)) { AnalyzerABTestLogger.Log(nameof(AnalyzerEnabledFlight)); // If we got true from the experimentation service, then we're in the treatment // group, and the experiment is enabled. We determine if the infobar has been // displayed in the past 24 hours. If it hasn't been displayed, then we do so now. var lastTimeInfoBarShown = DateTime.FromBinary(_workspace.Options.GetOption(AnalyzerABTestOptions.LastDateTimeInfoBarShown)); var utcNow = DateTime.UtcNow; var timeSinceLastShown = utcNow - lastTimeInfoBarShown; if (timeSinceLastShown.TotalDays >= 1) { _workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeInfoBarShown, utcNow.ToBinary()); AnalyzerABTestLogger.Log("InfoBarShown"); var infoBarService = _workspace.Services.GetRequiredService <IInfoBarService>(); infoBarService.ShowInfoBarInGlobalView( ServicesVSResources.Try_the_preview_version_of_our_live_code_analysis_extension_which_provides_more_fixes_for_common_API_design_naming_performance_and_reliability_issues, // Install link new InfoBarUI(title: ServicesVSResources.Learn_more, kind: InfoBarUI.UIKind.HyperLink, action: OpenInstallHyperlink), // Don't show the InfoBar again link new InfoBarUI(title: ServicesVSResources.Never_show_this_again, kind: InfoBarUI.UIKind.Button, action: DoNotShowAgain)); } } }
private bool IsCandidate() { // if this user ever participated in the experiement and then uninstall the vsix, then // this user will never be candidate again. if (_workspace.Options.GetOption(AnalyzerABTestOptions.ParticipatedInExperiment)) { return(false); } // Filter for valid A/B test candidates. Candidates fill the following critera: // 1: Are a Dotnet user (as evidenced by the fact that this code is being run) // 2: Have triggered a lightbulb on 3 separate days // If the user hasn't met candidacy conditions, then we check them. Otherwise, proceed // to info bar check var options = _workspace.Options; var isCandidate = options.GetOption(AnalyzerABTestOptions.HasMetCandidacyRequirements); if (!isCandidate) { // We store in UTC to avoid any timezone offset weirdness var lastTriggeredTimeBinary = options.GetOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction); AnalyzerABTestLogger.LogCandidacyRequirementsTracking(lastTriggeredTimeBinary); var lastTriggeredTime = DateTime.FromBinary(lastTriggeredTimeBinary); var currentTime = DateTime.UtcNow; var span = currentTime - lastTriggeredTime; if (span.TotalDays >= 1) { options = options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction, currentTime.ToBinary()); var usageCount = options.GetOption(AnalyzerABTestOptions.UsedSuggestedActionCount); options = options.WithChangedOption(AnalyzerABTestOptions.UsedSuggestedActionCount, ++usageCount); if (usageCount >= 3) { isCandidate = true; options = options.WithChangedOption(AnalyzerABTestOptions.HasMetCandidacyRequirements, true); AnalyzerABTestLogger.Log(nameof(AnalyzerABTestOptions.HasMetCandidacyRequirements)); } _workspace.Options = options; } } return(isCandidate); }
public async Task MergeAsync(ActiveFileState state, Document document) { Contract.ThrowIfFalse(state.DocumentId == document.Id); // merge active file state to project state var lastResult = _lastResult; var syntax = state.GetAnalysisData(AnalysisKind.Syntax); var semantic = state.GetAnalysisData(AnalysisKind.Semantic); AnalyzerABTestLogger.LogDocumentDiagnostics(document, _owner.StateName, syntax.Items, semantic.Items); var project = document.Project; // if project didn't successfully loaded, then it is same as FSA off var fullAnalysis = ServiceFeatureOnOffOptions.IsClosedFileDiagnosticsEnabled(project) && await project.HasSuccessfullyLoadedAsync(CancellationToken.None).ConfigureAwait(false); // keep from build flag if full analysis is off var fromBuild = fullAnalysis ? false : lastResult.FromBuild; var openFileOnlyAnalyzer = _owner.Analyzer.IsOpenFileOnly(document.Project.Solution.Workspace); // if it is allowed to keep project state, check versions and if they are same, bail out. // if full solution analysis is off or we are asked to reset document state, we always merge. if (fullAnalysis && !openFileOnlyAnalyzer && syntax.Version != VersionStamp.Default && syntax.Version == semantic.Version && syntax.Version == lastResult.Version) { // all data is in sync already. return; } // we have mixed versions or full analysis is off, set it to default so that it can be re-calculated next time so data can be in sync. var version = VersionStamp.Default; // serialization can't be cancelled. var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version); // save active file diagnostics back to project state await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, syntax.Items).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, semantic.Items).ConfigureAwait(false); // save last aggregated form of analysis result _lastResult = _lastResult.UpdateAggregatedResult(version, state.DocumentId, fromBuild); }
private bool IsVsixInstalled() { if (_installStatus == LiveCodeAnalysisInstallStatus.Unknown) { var vsShell = _serviceProvider.GetService(typeof(SVsShell)) as IVsShell; var hr = vsShell.IsPackageInstalled(FxCopAnalyzersPackageGuid, out int installed); if (ErrorHandler.Failed(hr)) { FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr)); // We set installed to ensure we don't go through this again next time a // suggested action is called, and we don't want to continue if the shell // is busted. _installStatus = LiveCodeAnalysisInstallStatus.Installed; } else { _installStatus = installed != 0 ? LiveCodeAnalysisInstallStatus.Installed : LiveCodeAnalysisInstallStatus.NotInstalled; AnalyzerABTestLogger.LogInstallationStatus(_workspace, _installStatus); } } return(_installStatus == LiveCodeAnalysisInstallStatus.Installed); }
public async Task SaveAsync(Project project, DiagnosticAnalysisResult result) { Contract.ThrowIfTrue(result.IsAggregatedForm); RemoveInMemoryCache(_lastResult); // save last aggregated form of analysis result _lastResult = result.ToAggregatedForm(); // serialization can't be cancelled. var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, result.Version); foreach (var documentId in result.DocumentIds) { var document = project.GetDocument(documentId); if (document == null) { // it can happen with build synchronization since, in build case, // we don't have actual snapshot (we have no idea what sources out of proc build has picked up) // so we might be out of sync. // example of such cases will be changing anything about solution while building is going on. // it can be user explict actions such as unloading project, deleting a file, but also it can be // something project system or roslyn workspace does such as populating workspace right after // solution is loaded. continue; } await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, GetResult(result, AnalysisKind.Syntax, document.Id)).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, GetResult(result, AnalysisKind.Semantic, document.Id)).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.NonLocalStateName, GetResult(result, AnalysisKind.NonLocal, document.Id)).ConfigureAwait(false); } await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false); AnalyzerABTestLogger.LogProjectDiagnostics(project, _owner.StateName, result); }
private void DoNotShowAgain() { _workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.NeverShowAgain, true); AnalyzerABTestLogger.Log(nameof(AnalyzerABTestOptions.NeverShowAgain)); }
private void OpenInstallHyperlink() { System.Diagnostics.Process.Start(AnalyzerVsixHyperlink); AnalyzerABTestLogger.Log(nameof(AnalyzerVsixHyperlink)); }