Skip to content

Commit

Permalink
Merge remote-tracking branch 'release/dev16.8' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Aug 14, 2020
2 parents 57bed47 + f40d28a commit d836751
Show file tree
Hide file tree
Showing 45 changed files with 645 additions and 281 deletions.
22 changes: 15 additions & 7 deletions azure-pipelines-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ jobs:
strategy:
maxParallel: 2
matrix:
debug_async:
debug_32:
_configuration: Debug
release_async:
_oop64bit: false
debug_64:
_configuration: Debug
_oop64bit: true
release_32:
_configuration: Release
_oop64bit: false
release_64:
_configuration: Release
_oop64bit: true
timeoutInMinutes: 135

steps:
- script: eng/cibuild.cmd -configuration $(_configuration) -prepareMachine -testVsi
- script: eng/cibuild.cmd -configuration $(_configuration) -prepareMachine -testVsi -oop64bit:$$(_oop64bit)
displayName: Build and Test

- task: PublishTestResults@2
Expand All @@ -38,14 +46,14 @@ jobs:
testRunner: XUnit
testResultsFiles: $(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)\*.xml
mergeTestResults: true
testRunTitle: '$(System.JobAttempt)-Integration $(_configuration)'
testRunTitle: '$(System.JobAttempt)-Integration $(_configuration) OOP64_$(_oop64bit)'
condition: always()

- task: PublishBuildArtifacts@1
displayName: Publish Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(_configuration)'
ArtifactName: '$(System.JobAttempt)-Logs $(_configuration) $(Build.BuildNumber)'
ArtifactName: '$(System.JobAttempt)-Logs $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
Expand All @@ -54,7 +62,7 @@ jobs:
displayName: Publish Secondary Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log2\$(_configuration)'
ArtifactName: '$(System.JobAttempt)-Secondary Logs $(_configuration) $(Build.BuildNumber)'
ArtifactName: '$(System.JobAttempt)-Secondary Logs $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
Expand All @@ -63,7 +71,7 @@ jobs:
displayName: Publish Screenshots
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\bin\Microsoft.VisualStudio.LanguageServices.IntegrationTests\$(_configuration)\net472\xUnitResults'
ArtifactName: '$(System.JobAttempt)-Screenshots $(_configuration) $(Build.BuildNumber)'
ArtifactName: '$(System.JobAttempt)-Screenshots $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
3 changes: 3 additions & 0 deletions eng/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ param (
[switch]$useGlobalNuGetCache = $true,
[switch]$warnAsError = $false,
[switch]$sourceBuild = $false,
[switch]$oop64bit = $true,

# official build settings
[string]$officialBuildId = "",
Expand Down Expand Up @@ -594,6 +595,8 @@ function Setup-IntegrationTestRun() {
# Make sure we can capture a screenshot. An exception at this point will fail-fast the build.
Capture-Screenshot $screenshotPath
}

$env:ROSLYN_OOP64BIT = "$oop64bit"
}

function Prepare-TempDir() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.CodeAnalysis.Text;
using System.Windows.Media;
using Microsoft.CodeAnalysis.DocumentationComments;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Editor;
Expand Down Expand Up @@ -65,11 +66,11 @@ private InlineParameterNameHintsTag(FrameworkElement adornment, ITextView textVi
/// <param name="textView">The view of the editor</param>
/// <param name="span">The span that has the location of the hint</param>
/// <param name="key">The symbolkey associated with each parameter</param>
public static InlineParameterNameHintsTag Create(string text, double lineHeight, TextFormattingRunProperties format,
ITextView textView, SnapshotSpan span, SymbolKey key,
public static InlineParameterNameHintsTag Create(string text, TextFormattingRunProperties format,
IWpfTextView textView, SnapshotSpan span, SymbolKey key,
InlineParameterNameHintsTaggerProvider taggerProvider)
{
return new InlineParameterNameHintsTag(CreateElement(text, lineHeight, format), textView,
return new InlineParameterNameHintsTag(CreateElement(text, textView, format), textView,
span, key, taggerProvider);
}

Expand Down Expand Up @@ -119,7 +120,7 @@ public async Task<IReadOnlyCollection<object>> CreateDescriptionAsync(Cancellati
return uiCollection;
}

private static FrameworkElement CreateElement(string text, double lineHeight, TextFormattingRunProperties format)
private static FrameworkElement CreateElement(string text, IWpfTextView textView, TextFormattingRunProperties format)
{
// Constructs the hint block which gets assigned parameter name and fontstyles according to the options
// page. Calculates a font size 1/4 smaller than the font size of the rest of the editor
Expand All @@ -145,13 +146,23 @@ private static FrameworkElement CreateElement(string text, double lineHeight, Te
Background = format.BackgroundBrush,
Child = block,
CornerRadius = new CornerRadius(2),
Height = lineHeight - (0.25 * lineHeight),
Height = textView.LineHeight - (0.25 * textView.LineHeight),
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(left: 0, top: -0.20 * lineHeight, right: 5, bottom: 0),
Margin = new Thickness(left: 0, top: -0.20 * textView.LineHeight, right: 5, bottom: 0),
Padding = new Thickness(1),
VerticalAlignment = VerticalAlignment.Center,

// Need to set SnapsToDevicePixels and UseLayoutRounding to avoid unnecessary reformatting
SnapsToDevicePixels = textView.VisualElement.SnapsToDevicePixels,
UseLayoutRounding = textView.VisualElement.UseLayoutRounding,
VerticalAlignment = VerticalAlignment.Center
};

// Need to set these properties to avoid unnecessary reformatting because some dependancy properties
// affect layout
TextOptions.SetTextFormattingMode(border, TextOptions.GetTextFormattingMode(textView.VisualElement));
TextOptions.SetTextHintingMode(border, TextOptions.GetTextHintingMode(textView.VisualElement));
TextOptions.SetTextRenderingMode(border, TextOptions.GetTextRenderingMode(textView.VisualElement));

border.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
return border;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
Expand Down Expand Up @@ -48,11 +46,11 @@ internal sealed class InlineParameterNameHintsTagger : ITagger<IntraTextAdornmen
private readonly InlineParameterNameHintsTaggerProvider _inlineParameterNameHintsTaggerProvider;

private readonly ITextBuffer _buffer;
private readonly ITextView _textView;
private readonly IWpfTextView _textView;

public event EventHandler<SnapshotSpanEventArgs>? TagsChanged;

public InlineParameterNameHintsTagger(InlineParameterNameHintsTaggerProvider taggerProvider, ITextView textView, ITextBuffer buffer, ITagAggregator<InlineParameterNameHintDataTag> tagAggregator)
public InlineParameterNameHintsTagger(InlineParameterNameHintsTaggerProvider taggerProvider, IWpfTextView textView, ITextBuffer buffer, ITagAggregator<InlineParameterNameHintDataTag> tagAggregator)
{
_cache = new List<ITagSpan<IntraTextAdornmentTag>>();

Expand Down Expand Up @@ -128,7 +126,7 @@ public IEnumerable<ITagSpan<IntraTextAdornmentTag>> GetTags(NormalizedSnapshotSp
{
var dataTagSpan = dataTagSpans[0];
var parameterHintSnapshotSpan = new SnapshotSpan(dataTagSpan.Start, 0);
var parameterHintUITag = InlineParameterNameHintsTag.Create(textTag.ParameterName, _textView.LineHeight,
var parameterHintUITag = InlineParameterNameHintsTag.Create(textTag.ParameterName,
Format, _textView, dataTagSpan, textTag.ParameterSymbolKey, _inlineParameterNameHintsTaggerProvider);

_cache.Add(new TagSpan<IntraTextAdornmentTag>(parameterHintSnapshotSpan, parameterHintUITag));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where
}

var tagAggregator = _viewTagAggregatorFactoryService.CreateTagAggregator<InlineParameterNameHintDataTag>(textView);
return new InlineParameterNameHintsTagger(this, textView, buffer, tagAggregator) as ITagger<T>;
return new InlineParameterNameHintsTagger(this, (IWpfTextView)textView, buffer, tagAggregator) as ITagger<T>;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.DesignerAttribute;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.DesignerAttribute
{
internal abstract partial class AbstractDesignerAttributeIncrementalAnalyzer : IncrementalAnalyzerBase
{
private const string DataKey = "DesignerAttributeData";

private readonly IPersistentStorageService _storageService;

protected AbstractDesignerAttributeIncrementalAnalyzer(Workspace workspace)
{
_storageService = workspace.Services.GetRequiredService<IPersistentStorageService>();
}

protected abstract Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken);

protected abstract Task ReportDesignerAttributeDataAsync(List<DesignerAttributeData> data, CancellationToken cancellationToken);

public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken)
=> ReportProjectRemovedAsync(projectId, cancellationToken);

public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken)
=> AnalyzeProjectAsync(project, specificDocument: null, cancellationToken);

public override Task AnalyzeDocumentAsync(Document document, SyntaxNode? body, InvocationReasons reasons, CancellationToken cancellationToken)
{
// don't need to reanalyze file if just a method body was edited. That can't
// affect designer attributes.
if (body != null)
return Task.CompletedTask;

// When we register our analyzer we will get called into for every document to
// 'reanalyze' them all. Ignore those as we would prefer to analyze the project
// en-mass.
if (reasons.Contains(PredefinedInvocationReasons.Reanalyze))
return Task.CompletedTask;

return AnalyzeProjectAsync(document.Project, document, cancellationToken);
}

private async Task AnalyzeProjectAsync(Project project, Document? specificDocument, CancellationToken cancellationToken)
{
if (!project.SupportsCompilation)
return;

// We need to reanalyze the project whenever it (or any of its dependencies) have
// changed. We need to know about dependencies since if a downstream project adds the
// DesignerCategory attribute to a class, that can affect us when we examine the classes
// in this project.
var projectVersion = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);

var latestInfos = await ComputeLatestInfosAsync(
project, projectVersion, specificDocument, cancellationToken).ConfigureAwait(false);

// Now get all the values that actually changed and notify VS about them. We don't need
// to tell it about the ones that didn't change since that will have no effect on the
// user experience.
//
// ! is safe here as `i.changed` implies `i.info` is non-null.
var changedInfos = latestInfos.Where(i => i.changed).Select(i => i.data!.Value).ToList();
if (changedInfos.Count > 0)
{
await ReportDesignerAttributeDataAsync(changedInfos, cancellationToken).ConfigureAwait(false);
}

// now that we've notified VS, persist all the infos we have (changed or otherwise) back
// to disk. We want to do this even when the data is unchanged so that our version
// stamps will be correct for the next time we come around to analyze this project.
//
// Note: we have a potential race condition here. Specifically, for simplicity, the VS
// side will return immediately, without actually notifying the project system. That
// means that we could persist the data to local storage that isn't in sync with what
// the project system knows about. i.e. if VS is closed or crashes before that
// information is persisted, then these two systems will be in disagreement. this is
// believed to not be a big issue given how small a time window this would be and how
// easy it would be to get out of that state (just edit the file).

await PersistLatestInfosAsync(project.Solution, projectVersion, latestInfos, cancellationToken).ConfigureAwait(false);
}

private async Task PersistLatestInfosAsync(
Solution solution, VersionStamp projectVersion, (Document, DesignerAttributeData? daa, bool changed)[] latestInfos, CancellationToken cancellationToken)
{
using var storage = _storageService.GetStorage(solution);

foreach (var (doc, info, _) in latestInfos)
{
// Skip documents that didn't change contents/version at all. No point in writing
// back out the exact same data as before.
if (info == null)
continue;

using var memoryStream = new MemoryStream();
using var writer = new ObjectWriter(memoryStream);

PersistInfoTo(writer, info.Value, projectVersion);

memoryStream.Position = 0;
await storage.WriteStreamAsync(
doc, DataKey, memoryStream, cancellationToken).ConfigureAwait(false);
}
}

private async Task<(Document, DesignerAttributeData? data, bool changed)[]> ComputeLatestInfosAsync(
Project project, VersionStamp projectVersion,
Document? specificDocument, CancellationToken cancellationToken)
{
using var storage = _storageService.GetStorage(project.Solution);

var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
var designerCategoryType = compilation.DesignerCategoryAttributeType();

using var _ = ArrayBuilder<Task<(Document, DesignerAttributeData?, bool changed)>>.GetInstance(out var tasks);
foreach (var document in project.Documents)
{
// If we're only analyzing a specific document, then skip the rest.
if (specificDocument != null && document != specificDocument)
continue;

tasks.Add(ComputeDesignerAttributeDataAsync(
storage, projectVersion, designerCategoryType, document, cancellationToken));
}

return await Task.WhenAll(tasks).ConfigureAwait(false);
}

private static async Task<(Document, DesignerAttributeData?, bool changed)> ComputeDesignerAttributeDataAsync(
IPersistentStorage storage, VersionStamp projectVersion, INamedTypeSymbol? designerCategoryType,
Document document, CancellationToken cancellationToken)
{
try
{
// If we don't have a path for this document, we cant proceed with it.
// We need that path to inform the project system which file we're referring to.
if (document.FilePath == null)
return default;

// First check and see if we have stored information for this doc and if that
// information is up to date.
using var stream = await storage.ReadStreamAsync(document, DataKey, cancellationToken).ConfigureAwait(false);
using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken);
var persisted = TryReadPersistedInfo(reader);
if (persisted.category != null && persisted.projectVersion == projectVersion)
{
// We were able to read out the old data, and it matches our current project
// version. Just return back that nothing changed here. We won't tell VS about
// this, and we won't re-persist this later.
return default;
}

// We either haven't computed the designer info, or our data was out of date. We need
// So recompute here. Figure out what the current category is, and if that's different
// from what we previously stored.
var category = await DesignerAttributeHelpers.ComputeDesignerAttributeCategoryAsync(
designerCategoryType, document, cancellationToken).ConfigureAwait(false);
var data = new DesignerAttributeData
{
Category = category,
DocumentId = document.Id,
FilePath = document.FilePath,
};

return (document, data, changed: category != persisted.category);
}
catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
{
return default;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
using Microsoft.CodeAnalysis.ErrorReporting;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Remote
namespace Microsoft.CodeAnalysis.DesignerAttribute
{
internal partial class RemoteDesignerAttributeIncrementalAnalyzer
internal partial class AbstractDesignerAttributeIncrementalAnalyzer
{
/// <summary>
/// Our current serialization format. Increment whenever it changes so that we don't read
Expand Down
Loading

0 comments on commit d836751

Please sign in to comment.