diff --git a/build.sh b/build.sh
index fd659a3dd15ea21c01b318c172753d50fcb7678f..e827a9d5ccb10af2b23802fbdde57ccf364ce0b3 100755
--- a/build.sh
+++ b/build.sh
@@ -122,6 +122,13 @@ then
build_args+=" /p:BootstrapBuildPath=${bootstrap_path}"
fi
+# https://github.com/dotnet/roslyn/issues/23736
+UNAME="$(uname)"
+if [[ "$UNAME" == "Darwin" ]]
+then
+ build_args+=" /p:UseRoslynAnalyzers=false"
+fi
+
if [[ "${build}" == true ]]
then
echo "Building Compilers.sln"
diff --git a/build/Targets/Versions.props b/build/Targets/Versions.props
index 795be0095393dae30672bb15fbdd0c4483c1cb61..70f759eb54dc6018635ba15577f8c0bb278ca358 100644
--- a/build/Targets/Versions.props
+++ b/build/Targets/Versions.props
@@ -14,7 +14,7 @@
dev
- beta2
+ beta3
$(RoslynFileVersionBase)-$(RoslynNuGetMoniker)
diff --git a/build/config/PublishData.json b/build/config/PublishData.json
index 1a99d2061e819de3eccd98fa47e5afe14182374e..a82232cf4c70789976c16f497f70f2d9994a5436 100644
--- a/build/config/PublishData.json
+++ b/build/config/PublishData.json
@@ -5,7 +5,14 @@
"version": "2.7.*",
"nuget": [ "https://dotnet.myget.org/F/roslyn/api/v2/package" ],
"vsix": [ "https://dotnet.myget.org/F/roslyn/vsix/upload" ],
- "channels": [ "dev15.6" ]
+ "channels": [ "dev15.6", "dev15.6p3" ]
+ },
+ "dev15.6-preview2-vs-deps": {
+ "nugetKind": "PerBuildPreRelease",
+ "version": "2.7.*",
+ "nuget": [ "https://dotnet.myget.org/F/roslyn/api/v2/package" ],
+ "vsix": [ "https://dotnet.myget.org/F/roslyn/vsix/upload" ],
+ "channels": [ "dev15.6p2" ]
},
"dev15.5.x": {
"nugetKind": "PerBuildPreRelease",
diff --git a/build/scripts/tests.sh b/build/scripts/tests.sh
index c37af5f1c1dabbb850c4542bf55a2fb29d23c881..9dc645094b1d585fa744665006143a5c10b028df 100755
--- a/build/scripts/tests.sh
+++ b/build/scripts/tests.sh
@@ -45,8 +45,8 @@ do
runtimeconfig_json="${file_name%.*}".runtimeconfig.json
# If the user specifies a test on the command line, only run that one
- # "${2:-}" => take second arg, empty string if unset (regex always matches if empty)
- if [[ ! "${file_name}" =~ "${2:-}" ]]
+ # "${2:-}" => take second arg, empty string if unset
+ if [[ ("${2:-}" != "") && (! "${file_name}" =~ "${2:-}") ]]
then
echo "Skipping ${file_name}"
continue
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs
index 276e2de3335668542e0fdaf5d8ca76d8ab908b8b..46c6af1a94164da8bc3862f2ecfbeaf75b52a80a 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs
@@ -305,14 +305,14 @@ internal virtual ImportChain ImportChain
}
///
- /// Get that can be used to quickly
- /// check for TypeIdentifier attribute applications in context of this binder.
+ /// Get that can be used to quickly
+ /// check for certain attribute applications in context of this binder.
///
- internal virtual QuickTypeIdentifierAttributeChecker QuickTypeIdentifierAttributeChecker
+ internal virtual QuickAttributeChecker QuickAttributeChecker
{
get
{
- return _next.QuickTypeIdentifierAttributeChecker;
+ return _next.QuickAttributeChecker;
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs
index 028f4596341921d3cc62d381809b0ca8e86ed84b..15012a853822ed12ce50676355ef55b73a359433 100644
--- a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs
@@ -28,14 +28,14 @@ internal override ImportChain ImportChain
}
///
- /// Get that can be used to quickly
- /// check for TypeIdentifier attribute applications in context of this binder.
+ /// Get that can be used to quickly
+ /// check for certain attribute applications in context of this binder.
///
- internal override QuickTypeIdentifierAttributeChecker QuickTypeIdentifierAttributeChecker
+ internal override QuickAttributeChecker QuickAttributeChecker
{
get
{
- return QuickTypeIdentifierAttributeChecker.Predefined;
+ return QuickAttributeChecker.Predefined;
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs
index 104ccc68d4d7f2aa5e7f67fede78bf004be3ec4a..e9b032db42d0c76b5665a72e54e361495dca2220 100644
--- a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs
@@ -21,7 +21,8 @@ internal sealed class InContainerBinder : Binder
private readonly Func, Imports> _computeImports;
private Imports _lazyImports;
private ImportChain _lazyImportChain;
- private QuickTypeIdentifierAttributeChecker _lazyQuickTypeIdentifierAttributeChecker;
+ private QuickAttributeChecker _lazyQuickAttributeChecker;
+ private readonly SyntaxList _usingsSyntax;
///
/// Creates a binder for a container with imports (usings and extern aliases) that can be
@@ -35,6 +36,20 @@ internal InContainerBinder(NamespaceOrTypeSymbol container, Binder next, CSharpS
_container = container;
_computeImports = basesBeingResolved => Imports.FromSyntax(declarationSyntax, this, basesBeingResolved, inUsing);
+
+ if (!inUsing)
+ {
+ if (declarationSyntax.Kind() == SyntaxKind.CompilationUnit)
+ {
+ var compilationUnit = (CompilationUnitSyntax)declarationSyntax;
+ _usingsSyntax = compilationUnit.Usings;
+ }
+ else if (declarationSyntax.Kind() == SyntaxKind.NamespaceDeclaration)
+ {
+ var namespaceDecl = (NamespaceDeclarationSyntax)declarationSyntax;
+ _usingsSyntax = namespaceDecl.Usings;
+ }
+ }
}
///
@@ -103,26 +118,26 @@ internal override ImportChain ImportChain
}
///
- /// Get that can be used to quickly
- /// check for TypeIdentifier attribute applications in context of this binder.
+ /// Get that can be used to quickly
+ /// check for certain attribute applications in context of this binder.
///
- internal override QuickTypeIdentifierAttributeChecker QuickTypeIdentifierAttributeChecker
+ internal override QuickAttributeChecker QuickAttributeChecker
{
get
{
- if (_lazyQuickTypeIdentifierAttributeChecker == null)
+ if (_lazyQuickAttributeChecker == null)
{
- QuickTypeIdentifierAttributeChecker result = this.Next.QuickTypeIdentifierAttributeChecker;
+ QuickAttributeChecker result = this.Next.QuickAttributeChecker;
if ((object)_container == null || _container.Kind == SymbolKind.Namespace)
{
- result = result.AddAliasesIfAny(GetImports(basesBeingResolved: null).UsingAliases);
+ result = result.AddAliasesIfAny(_usingsSyntax);
}
- _lazyQuickTypeIdentifierAttributeChecker = result;
+ _lazyQuickAttributeChecker = result;
}
- return _lazyQuickTypeIdentifierAttributeChecker;
+ return _lazyQuickAttributeChecker;
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs b/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2377262444f15d917e15d18fce05c68a13d3b390
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/QuickAttributeChecker.cs
@@ -0,0 +1,139 @@
+// 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.Diagnostics;
+using System.Threading;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Microsoft.CodeAnalysis.CSharp.Symbols
+{
+ ///
+ /// The QuickAttributeChecker applies a simple fast heuristic for determining probable
+ /// attributes of certain kinds without binding attribute types, just by looking at the final syntax of an
+ /// attribute usage.
+ ///
+ ///
+ /// It works by maintaining a dictionary of all possible simple names that might map to the given
+ /// attribute.
+ ///
+ internal sealed class QuickAttributeChecker
+ {
+ private readonly Dictionary _nameToAttributeMap;
+ private static QuickAttributeChecker _lazyPredefinedQuickAttributeChecker;
+
+#if DEBUG
+ private bool _sealed;
+#endif
+
+ internal static QuickAttributeChecker Predefined
+ {
+ get
+ {
+ if (_lazyPredefinedQuickAttributeChecker is null)
+ {
+ Interlocked.CompareExchange(ref _lazyPredefinedQuickAttributeChecker, CreatePredefinedQuickAttributeChecker(), null);
+ }
+
+ return _lazyPredefinedQuickAttributeChecker;
+ }
+ }
+
+ private static QuickAttributeChecker CreatePredefinedQuickAttributeChecker()
+ {
+ var result = new QuickAttributeChecker();
+ result.AddName(AttributeDescription.TypeIdentifierAttribute.Name, QuickAttributes.TypeIdentifier);
+ result.AddName(AttributeDescription.TypeForwardedToAttribute.Name, QuickAttributes.TypeForwardedTo);
+
+#if DEBUG
+ result._sealed = true;
+#endif
+ return result;
+ }
+
+ private QuickAttributeChecker()
+ {
+ _nameToAttributeMap = new Dictionary(StringComparer.Ordinal);
+ // NOTE: caller must seal
+ }
+
+ private QuickAttributeChecker(QuickAttributeChecker previous)
+ {
+ _nameToAttributeMap = new Dictionary(previous._nameToAttributeMap, StringComparer.Ordinal);
+ // NOTE: caller must seal
+ }
+
+ private void AddName(string name, QuickAttributes newAttributes)
+ {
+#if DEBUG
+ Debug.Assert(!_sealed);
+#endif
+ var currentValue = QuickAttributes.None;
+ _nameToAttributeMap.TryGetValue(name, out currentValue);
+
+ QuickAttributes newValue = newAttributes | currentValue;
+ _nameToAttributeMap[name] = newValue;
+ }
+
+ internal QuickAttributeChecker AddAliasesIfAny(SyntaxList usingsSyntax)
+ {
+ if (usingsSyntax.Count == 0)
+ {
+ return this;
+ }
+
+ QuickAttributeChecker newChecker = null;
+
+ foreach (var usingDirective in usingsSyntax)
+ {
+ if (usingDirective.Alias != null)
+ {
+ string name = usingDirective.Alias.Name.Identifier.ValueText;
+ string target = usingDirective.Name.GetUnqualifiedName().Identifier.ValueText;
+
+ if (_nameToAttributeMap.TryGetValue(target, out var foundAttributes))
+ {
+ // copy the QuickAttributes from alias target to alias name
+ (newChecker ?? (newChecker = new QuickAttributeChecker(this))).AddName(name, foundAttributes);
+ }
+ }
+ }
+
+ if (newChecker != null)
+ {
+#if DEBUG
+ newChecker._sealed = true;
+#endif
+ return newChecker;
+ }
+
+ return this;
+ }
+
+ public bool IsPossibleMatch(AttributeSyntax attr, QuickAttributes pattern)
+ {
+#if DEBUG
+ Debug.Assert(_sealed);
+#endif
+ string name = attr.Name.GetUnqualifiedName().Identifier.ValueText;
+ QuickAttributes foundAttributes;
+
+ // We allow "Name" to bind to "NameAttribute"
+ if (_nameToAttributeMap.TryGetValue(name, out foundAttributes) ||
+ _nameToAttributeMap.TryGetValue(name + "Attribute", out foundAttributes))
+ {
+ return (foundAttributes & pattern) != 0;
+ }
+
+ return false;
+ }
+ }
+
+ [Flags]
+ internal enum QuickAttributes : byte
+ {
+ None = 0,
+ TypeIdentifier = 1 << 0,
+ TypeForwardedTo = 2 << 0
+ }
+}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/QuickTypeIdentifierAttributeChecker.cs b/src/Compilers/CSharp/Portable/Symbols/Source/QuickTypeIdentifierAttributeChecker.cs
deleted file mode 100644
index 1cb49c8bbe2355274f97dce2ca87f588bdb8fd4d..0000000000000000000000000000000000000000
--- a/src/Compilers/CSharp/Portable/Symbols/Source/QuickTypeIdentifierAttributeChecker.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Microsoft.CodeAnalysis.CSharp.Symbols
-{
- ///
- /// The QuickTypeIdentifierAttributeChecker applies a simple fast heuristic for determining probable
- /// TypeIdentifier attributes without binding attribute types, just by looking at the final syntax of an
- /// attribute usage. It is accessed via the QuickTypeIdentifierAttributeChecker property on Binder.
- ///
- ///
- /// It works by maintaining a dictionary of all possible simple names that might map to a TypeIdentifier
- /// attribute.
- ///
- internal class QuickTypeIdentifierAttributeChecker
- {
- private readonly HashSet _candidates;
-#if DEBUG
- private bool _sealed;
-#endif
-
- public static readonly QuickTypeIdentifierAttributeChecker Predefined = new QuickTypeIdentifierAttributeChecker();
-
- private QuickTypeIdentifierAttributeChecker()
- {
- _candidates = new HashSet();
- _candidates.Add(AttributeDescription.TypeIdentifierAttribute.Name);
-#if DEBUG
- _sealed = true;
-#endif
- }
-
- private QuickTypeIdentifierAttributeChecker(QuickTypeIdentifierAttributeChecker previous)
- {
- _candidates = new HashSet(previous._candidates);
- }
-
- private void AddCandidate(string candidate)
- {
-#if DEBUG
- Debug.Assert(!_sealed);
-#endif
- _candidates.Add(candidate);
- }
-
- public QuickTypeIdentifierAttributeChecker AddAliasesIfAny(ImmutableDictionary usingAliases)
- {
- QuickTypeIdentifierAttributeChecker newChecker = null;
-
- foreach (KeyValuePair pair in usingAliases)
- {
- if (_candidates.Contains(pair.Value.UsingDirective.Name.GetUnqualifiedName().Identifier.ValueText))
- {
- (newChecker ?? (newChecker = new QuickTypeIdentifierAttributeChecker(this))).AddCandidate(pair.Key);
- }
- }
-
- if (newChecker != null)
- {
-#if DEBUG
- newChecker._sealed = true;
-#endif
- return newChecker;
- }
-
- return this;
- }
-
- public bool IsPossibleMatch(AttributeSyntax attr)
- {
-#if DEBUG
- Debug.Assert(_sealed);
-#endif
- string name = attr.Name.GetUnqualifiedName().Identifier.ValueText;
- return _candidates.Contains(name) || _candidates.Contains(name + "Attribute");
- }
- }
-}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
index bf50bfba4ff0ff9e1609cb016bf2b4cb4f37ca3d..5844d04ee6b64a04d861819e46f3262703ac6314 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
@@ -1556,6 +1556,33 @@ internal CommonAssemblyWellKnownAttributeData GetSourceDecodedWellKnownAttribute
return (CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
}
+ ///
+ /// This only forces binding of attributes that look like they may be forwarded types attributes (syntactically).
+ ///
+ internal HashSet GetForwardedTypes()
+ {
+ CustomAttributesBag attributesBag = _lazySourceAttributesBag;
+ if (attributesBag?.IsDecodedWellKnownAttributeDataComputed == true)
+ {
+ // Use already decoded attributes
+ return ((CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData)?.ForwardedTypes;
+ }
+
+ attributesBag = null;
+ LoadAndValidateAttributes(OneOrMany.Create(GetAttributeDeclarations()), ref attributesBag, attributeMatchesOpt: this.IsPossibleForwardedTypesAttribute);
+
+ var wellKnownAttributeData = (CommonAssemblyWellKnownAttributeData)attributesBag?.DecodedWellKnownAttributeData;
+ return wellKnownAttributeData?.ForwardedTypes;
+ }
+
+ private bool IsPossibleForwardedTypesAttribute(AttributeSyntax node)
+ {
+ QuickAttributeChecker checker =
+ this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker;
+
+ return checker.IsPossibleMatch(node, QuickAttributes.TypeForwardedTo);
+ }
+
private static IEnumerable GetSecurityAttributes(CustomAttributesBag attributesBag)
{
Debug.Assert(attributesBag.IsSealed);
@@ -2556,13 +2583,14 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti
if (_lazyForwardedTypesFromSource == null)
{
IDictionary forwardedTypesFromSource;
- CommonAssemblyWellKnownAttributeData wellKnownAttributeData = GetSourceDecodedWellKnownAttributeData();
+ // Get the TypeForwardedTo attributes with minimal binding to avoid cycle problems
+ HashSet forwardedTypes = GetForwardedTypes();
- if (wellKnownAttributeData != null && wellKnownAttributeData.ForwardedTypes != null)
+ if (forwardedTypes != null)
{
forwardedTypesFromSource = new Dictionary(StringOrdinalComparer.Instance);
- foreach (NamedTypeSymbol forwardedType in wellKnownAttributeData.ForwardedTypes)
+ foreach (NamedTypeSymbol forwardedType in forwardedTypes)
{
NamedTypeSymbol originalDefinition = forwardedType.OriginalDefinition;
Debug.Assert((object)originalDefinition.ContainingType == null, "How did a nested type get forwarded?");
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
index de5c0fe47574813ff63f44ca98a9d820f50e1cae..8de5fc066cdcb6d50cc0ee4f00f3b964337e3f81 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
@@ -780,13 +780,13 @@ private void CheckPresenceOfTypeIdentifierAttribute()
foreach (SyntaxList list in attributeLists)
{
var syntaxTree = list.Node.SyntaxTree;
- QuickTypeIdentifierAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(list.Node.SyntaxTree).GetBinder(list.Node).QuickTypeIdentifierAttributeChecker;
+ QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(list.Node.SyntaxTree).GetBinder(list.Node).QuickAttributeChecker;
foreach (AttributeListSyntax attrList in list)
{
foreach (AttributeSyntax attr in attrList.Attributes)
{
- if (checker.IsPossibleMatch(attr))
+ if (checker.IsPossibleMatch(attr, QuickAttributes.TypeIdentifier))
{
// This attribute syntax might be an application of TypeIdentifierAttribute.
// Let's bind it.
diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
index baca5d8c6928c8410869329403a2be9d02b9726f..223d85128e59dc3c6fb1aca960842b48742631fb 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
@@ -255,19 +255,21 @@ internal virtual void PostDecodeWellKnownAttributes(ImmutableArraySpecific part of the symbol to which the attributes apply, or if the attributes apply to the symbol itself.
/// Indicates that only early decoding should be performed. WARNING: the resulting bag will not be sealed.
/// Binder to use. If null, GetBinderFactory will be used.
+ /// If specified, only load attributes that match this predicate, and any diagnostics produced will be dropped.
/// Flag indicating whether lazyCustomAttributes were stored on this thread. Caller should check for this flag and perform NotePartComplete if true.
internal bool LoadAndValidateAttributes(
OneOrMany> attributesSyntaxLists,
ref CustomAttributesBag lazyCustomAttributesBag,
AttributeLocation symbolPart = AttributeLocation.None,
bool earlyDecodingOnly = false,
- Binder binderOpt = null)
+ Binder binderOpt = null,
+ Func attributeMatchesOpt = null)
{
var diagnostics = DiagnosticBag.GetInstance();
var compilation = this.DeclaringCompilation;
ImmutableArray binders;
- ImmutableArray attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, binderOpt, out binders);
+ ImmutableArray attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, attributeMatchesOpt, binderOpt, out binders);
Debug.Assert(!attributesToBind.IsDefault);
ImmutableArray boundAttributes;
@@ -344,8 +346,11 @@ internal virtual void PostDecodeWellKnownAttributes(ImmutableArray.Empty;
}
@@ -382,6 +387,7 @@ private void RecordPresenceOfBadAttributes(ImmutableArray b
AttributeLocation symbolPart,
DiagnosticBag diagnostics,
CSharpCompilation compilation,
+ Func attributeMatchesOpt,
Binder rootBinderOpt,
out ImmutableArray binders)
{
@@ -409,8 +415,22 @@ private void RecordPresenceOfBadAttributes(ImmutableArray b
}
var attributesToBind = attributeDeclarationSyntax.Attributes;
- syntaxBuilder.AddRange(attributesToBind);
- attributesToBindCount += attributesToBind.Count;
+ if (attributeMatchesOpt is null)
+ {
+ syntaxBuilder.AddRange(attributesToBind);
+ attributesToBindCount += attributesToBind.Count;
+ }
+ else
+ {
+ foreach (var attribute in attributesToBind)
+ {
+ if (attributeMatchesOpt(attribute))
+ {
+ syntaxBuilder.Add(attribute);
+ attributesToBindCount++;
+ }
+ }
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
index 068ee4d42b4357f50c1b4a2ad3c8ed7673d587dc..b4ac9d40a3b5aeea2808e83e679d9cf5d3e10422 100644
--- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
+++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
@@ -4368,6 +4368,24 @@ public void PublicSign_KeyFileRelativePath()
Assert.Equal(Path.Combine(_baseDirectory, "test.snk"), parsedArgs.CompilationOptions.CryptoKeyFile);
}
+ [Fact]
+ [WorkItem(11497, "https://github.com/dotnet/roslyn/issues/11497")]
+ public void PublicSignWithEmptyKeyPath()
+ {
+ DefaultParse(new[] { "/publicsign", "/keyfile:", "a.cs" }, _baseDirectory).Errors.Verify(
+ // error CS2005: Missing file specification for 'keyfile' option
+ Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("keyfile").WithLocation(1, 1));
+ }
+
+ [Fact]
+ [WorkItem(11497, "https://github.com/dotnet/roslyn/issues/11497")]
+ public void PublicSignWithEmptyKeyPath2()
+ {
+ DefaultParse(new[] { "/publicsign", "/keyfile:\"\"", "a.cs" }, _baseDirectory).Errors.Verify(
+ // error CS2005: Missing file specification for 'keyfile' option
+ Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("keyfile").WithLocation(1, 1));
+ }
+
[WorkItem(546301, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546301")]
[Fact]
public void SubsystemVersionTests()
diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs
index 7326078254e03711843766ece0ddd7e1ae185b68..061a49009050119fa4279e7d7f90fb2ac7c64a27 100644
--- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs
@@ -25,6 +25,426 @@ public class AttributeTests : WellKnownAttributesTestBase
#region Function Tests
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void TestQuickAttributeChecker()
+ {
+ var predefined = QuickAttributeChecker.Predefined;
+ var typeForwardedTo = SyntaxFactory.Attribute(SyntaxFactory.ParseName("TypeForwardedTo"));
+ var typeIdentifier = SyntaxFactory.Attribute(SyntaxFactory.ParseName("TypeIdentifier"));
+
+ Assert.True(predefined.IsPossibleMatch(typeForwardedTo, QuickAttributes.TypeForwardedTo));
+ Assert.False(predefined.IsPossibleMatch(typeForwardedTo, QuickAttributes.TypeIdentifier));
+ Assert.False(predefined.IsPossibleMatch(typeForwardedTo, QuickAttributes.None));
+
+ Assert.False(predefined.IsPossibleMatch(typeIdentifier, QuickAttributes.TypeForwardedTo));
+ Assert.True(predefined.IsPossibleMatch(typeIdentifier, QuickAttributes.TypeIdentifier));
+ Assert.False(predefined.IsPossibleMatch(typeIdentifier, QuickAttributes.None));
+
+ var alias1 = SyntaxFactory.Attribute(SyntaxFactory.ParseName("alias1"));
+ var checker1 = WithAliases(predefined, "using alias1 = TypeForwardedToAttribute;");
+ Assert.True(checker1.IsPossibleMatch(alias1, QuickAttributes.TypeForwardedTo));
+ Assert.False(checker1.IsPossibleMatch(alias1, QuickAttributes.TypeIdentifier));
+
+ var checker1a = WithAliases(checker1, "using alias1 = TypeIdentifierAttribute;");
+ Assert.True(checker1a.IsPossibleMatch(alias1, QuickAttributes.TypeForwardedTo));
+ Assert.True(checker1a.IsPossibleMatch(alias1, QuickAttributes.TypeIdentifier));
+
+ var checker1b = WithAliases(checker1, "using alias2 = TypeIdentifierAttribute;");
+ var alias2 = SyntaxFactory.Attribute(SyntaxFactory.ParseName("alias2"));
+ Assert.True(checker1b.IsPossibleMatch(alias1, QuickAttributes.TypeForwardedTo));
+ Assert.False(checker1b.IsPossibleMatch(alias1, QuickAttributes.TypeIdentifier));
+ Assert.False(checker1b.IsPossibleMatch(alias2, QuickAttributes.TypeForwardedTo));
+ Assert.True(checker1b.IsPossibleMatch(alias2, QuickAttributes.TypeIdentifier));
+
+ var checker3 = WithAliases(predefined, "using alias3 = TypeForwardedToAttribute; using alias3 = TypeIdentifierAttribute;");
+ var alias3 = SyntaxFactory.Attribute(SyntaxFactory.ParseName("alias3"));
+ Assert.True(checker3.IsPossibleMatch(alias3, QuickAttributes.TypeForwardedTo));
+ Assert.True(checker3.IsPossibleMatch(alias3, QuickAttributes.TypeIdentifier));
+
+ QuickAttributeChecker WithAliases(QuickAttributeChecker checker, string aliases)
+ {
+ var nodes = Parse(aliases).GetRoot().DescendantNodes().OfType();
+ var list = new SyntaxList().AddRange(nodes);
+ return checker.AddAliasesIfAny(list);
+ }
+ }
+
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithMissingType_WithIrrelevantType()
+ {
+ var origLib_cs = @"public class C { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll want to lookup type C in 'lib' (during overload resolution of attribute constructors) albeit irrelevant
+// but C won't exist
+";
+
+ var reference_cs =
+@"using System;
+public class RefersToLibAttribute : Attribute
+{
+ public RefersToLibAttribute() { }
+ public RefersToLibAttribute(C c) { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithDiagnostic()
+ {
+ var origLib_cs = @"public class C { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(1)]
+";
+
+ var reference_cs =
+@"using System;
+public class RefersToLibAttribute : Attribute
+{
+ public RefersToLibAttribute() { }
+ public RefersToLibAttribute(C c) { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics(
+ // (3,60): error CS1503: Argument 1: cannot convert from 'int' to 'System.Type'
+ // [assembly: System.Runtime.CompilerServices.TypeForwardedTo(1)]
+ Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("1", "int", "System.Type").WithLocation(3, 60)
+ );
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics(
+ // (3,60): error CS1503: Argument 1: cannot convert from 'int' to 'System.Type'
+ // [assembly: System.Runtime.CompilerServices.TypeForwardedTo(1)]
+ Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("1", "int", "System.Type").WithLocation(3, 60)
+ );
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithMissingType_WithRelevantType()
+ {
+ var origLib_cs = @"public class C : System.Attribute { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll need to find type C in 'lib'
+// but C won't exist
+";
+
+ var reference_cs =
+@"
+public class RefersToLibAttribute : C
+{
+ public RefersToLibAttribute() { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics(
+ // (2,12): error CS7068: Reference to type 'C' claims it is defined in this assembly, but it is not defined in source or any added modules
+ // [assembly: RefersToLib] // to bind this, we'll want to lookup type C in 'lib'
+ Diagnostic(ErrorCode.ERR_MissingTypeInSource, "RefersToLib").WithArguments("C").WithLocation(2, 12)
+ );
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics(
+ // (2,12): error CS7068: Reference to type 'C' claims it is defined in this assembly, but it is not defined in source or any added modules
+ // [assembly: RefersToLib] // to bind this, we'll want to lookup type C in 'lib'
+ Diagnostic(ErrorCode.ERR_MissingTypeInSource, "RefersToLib").WithArguments("C").WithLocation(2, 12)
+ );
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithStaticUsing()
+ {
+ var origLib_cs = @"public class C : System.Attribute { }";
+
+ var newLib_cs = @"
+using static RefersToLibAttribute;
+ // Binding this will cause a lookup for 'C' in 'lib'.
+ // Such lookup requires binding 'TypeForwardedTo' attributes (and aliases), but we should not bind other usings, to avoid an infinite recursion.
+
+[assembly: System.Reflection.AssemblyTitleAttribute(""title"")]
+
+public class Ignore
+{
+ public void UseStaticUsing() { Method(); }
+}
+";
+
+ var reference_cs =
+@"
+public class RefersToLibAttribute : C
+{
+ public RefersToLibAttribute() { }
+ public static void Method() { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithTypeForward_WithIrrelevantType()
+ {
+ var origLib_cs = @"public class C { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll want to lookup type C in 'lib' (during overload resolution of attribute constructors) albeit irrelevant
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] // but C is forwarded
+";
+
+ var reference_cs =
+@"using System;
+public class RefersToLibAttribute : Attribute
+{
+ public RefersToLibAttribute() { }
+ public RefersToLibAttribute(C c) { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var newComp = CreateStandardCompilation(origLib_cs, assemblyName: "new");
+ newComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs,
+ references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs,
+ references: new[] { compWithReferenceToLib.ToMetadataReference(), newComp.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithTypeForward_WithRelevantType()
+ {
+ var origLib_cs = @"public class C : System.Attribute { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll need to find type C in 'lib'
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] // but C is forwarded
+";
+
+ var reference_cs =
+@"
+public class RefersToLibAttribute : C
+{
+ public RefersToLibAttribute() { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var newComp = CreateStandardCompilation(origLib_cs, assemblyName: "new");
+ newComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference(), newComp.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+
+ var newLibComp3 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp3.SourceAssembly.GetAttributes();
+ newLibComp3.VerifyDiagnostics();
+ }
+
+ ///
+ /// Looking up C explicitly after calling GetAttributes will cause to use the cached attributes, rather that do partial binding
+ ///
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithCheckAttributes()
+ {
+ var cDefinition_cs = @"public class C { }";
+ var derivedDefinition_cs = @"public class Derived : C { }";
+
+ var typeForward_cs = @"
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))]
+";
+
+ var origLibComp = CreateStandardCompilation(cDefinition_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var compWithDerivedAndReferenceToLib = CreateStandardCompilation(typeForward_cs + derivedDefinition_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithDerivedAndReferenceToLib .VerifyDiagnostics();
+
+ var compWithC = CreateStandardCompilation(cDefinition_cs, assemblyName: "new");
+ compWithC.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(typeForward_cs, references: new[] { compWithDerivedAndReferenceToLib.EmitToImageReference(), compWithC.EmitToImageReference() }, assemblyName: "lib");
+ var attribute = newLibComp.SourceAssembly.GetAttributes().Single(); // GetAttributes binds all attributes
+ Assert.Equal("System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(C))", attribute.ToString());
+
+ var derived = (NamedTypeSymbol)newLibComp.GetMember("Derived");
+ var c = derived.BaseType; // get C
+ Assert.Equal("C", c.ToTestDisplayString());
+ Assert.False(c.IsErrorType());
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithTypeForward_WithRelevantType_WithAlias()
+ {
+ var origLib_cs = @"public class C : System.Attribute { }";
+
+ var newLib_cs = @"
+using alias1 = System.Runtime.CompilerServices.TypeForwardedToAttribute;
+[assembly: RefersToLib] // to bind this, we'll need to find type C in 'lib'
+[assembly: alias1(typeof(C))] // but C is forwarded via alias
+";
+
+ var reference_cs =
+@"
+public class RefersToLibAttribute : C
+{
+ public RefersToLibAttribute() { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var newComp = CreateStandardCompilation(origLib_cs, assemblyName: "new");
+ newComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs,
+ references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs,
+ references: new[] { compWithReferenceToLib.ToMetadataReference(), newComp.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithExistingType_WithIrrelevantType()
+ {
+ var origLib_cs = @"public class C { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll want to lookup type C in 'lib' (during overload resolution of attribute constructors) albeit irrelevant
+public class C { } // and C exists here
+";
+
+ var reference_cs =
+@"using System;
+public class RefersToLibAttribute : Attribute
+{
+ public RefersToLibAttribute() { }
+ public RefersToLibAttribute(C c) { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var newComp = CreateStandardCompilation(origLib_cs, assemblyName: "new");
+ newComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference(), newComp.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(21194, "https://github.com/dotnet/roslyn/issues/21194")]
+ public void AttributeWithTypeReferenceToCurrentCompilation_WithExistingType_WithRelevantType()
+ {
+ var origLib_cs = @"public class C : System.Attribute { }";
+
+ var newLib_cs = @"
+[assembly: RefersToLib] // to bind this, we'll need to find type C in 'lib'
+public class C : System.Attribute { } // and C exists here
+";
+
+ var reference_cs =
+@"
+public class RefersToLibAttribute : C
+{
+ public RefersToLibAttribute() { }
+}
+";
+
+ var origLibComp = CreateStandardCompilation(origLib_cs, assemblyName: "lib");
+ origLibComp.VerifyDiagnostics();
+
+ var newComp = CreateStandardCompilation(origLib_cs, assemblyName: "new");
+ newComp.VerifyDiagnostics();
+
+ var compWithReferenceToLib = CreateStandardCompilation(reference_cs, references: new[] { origLibComp.EmitToImageReference() });
+ compWithReferenceToLib.VerifyDiagnostics();
+
+ var newLibComp = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.EmitToImageReference(), newComp.EmitToImageReference() }, assemblyName: "lib");
+ newLibComp.VerifyDiagnostics();
+
+ var newLibComp2 = CreateStandardCompilation(newLib_cs, references: new[] { compWithReferenceToLib.ToMetadataReference(), newComp.ToMetadataReference() }, assemblyName: "lib");
+ newLibComp2.VerifyDiagnostics();
+ }
+
[Fact]
public void TestAssemblyAttributes()
{
diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs
index 41d2f65dbe6c172c3a6fd661a2d5371e99284a2a..bfbc95a09b9e849bfb5ca9dbc0a7adefe08b1797 100644
--- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs
@@ -45,6 +45,26 @@ public void PublicSignWithRelativeKeyPath()
);
}
+ [Fact]
+ [WorkItem(11497, "https://github.com/dotnet/roslyn/issues/11497")]
+ public void PublicSignWithEmptyKeyPath()
+ {
+ CreateStandardCompilation("", options: TestOptions.ReleaseDll.WithPublicSign(true).WithCryptoKeyFile("")).VerifyDiagnostics(
+ // error CS8102: Public signing was specified and requires a public key, but no public key was specified.
+ Diagnostic(ErrorCode.ERR_PublicSignButNoKey).WithLocation(1, 1));
+ }
+
+ [Fact]
+ [WorkItem(11497, "https://github.com/dotnet/roslyn/issues/11497")]
+ public void PublicSignWithEmptyKeyPath2()
+ {
+ CreateStandardCompilation("", options: TestOptions.ReleaseDll.WithPublicSign(true).WithCryptoKeyFile("\"\"")).VerifyDiagnostics(
+ // error CS8106: Option 'CryptoKeyFile' must be an absolute path.
+ Diagnostic(ErrorCode.ERR_OptionMustBeAbsolutePath).WithArguments("CryptoKeyFile").WithLocation(1, 1),
+ // error CS8102: Public signing was specified and requires a public key, but no public key was specified.
+ Diagnostic(ErrorCode.ERR_PublicSignButNoKey).WithLocation(1, 1));
+ }
+
[Fact]
[WorkItem(233669, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=233669")]
public void CompilationName()
diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb
index bd6ffbe268497f8d0674680ba9336939b35f50a9..cfc1276dc2dbfb1f1f985e71a2b9e282124a6791 100644
--- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb
+++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb
@@ -8374,7 +8374,6 @@ End Class
Assert.False(args.CompilationOptions.PublicSign)
End Sub
-
Public Sub PublicSign_KeyFileRelativePath()
@@ -8383,6 +8382,20 @@ End Class
parsedArgs.Errors.Verify()
End Sub
+
+
+ Public Sub PublicSignWithEmptyKeyPath()
+ Dim parsedArgs = FullParse("/publicsign /keyfile: a.cs", _baseDirectory)
+ parsedArgs.Errors.Verify(Diagnostic(ERRID.ERR_ArgumentRequired).WithArguments("keyfile", ":").WithLocation(1, 1))
+ End Sub
+
+
+
+ Public Sub PublicSignWithEmptyKeyPath2()
+ Dim parsedArgs = FullParse("/publicsign /keyfile:"""" a.cs", _baseDirectory)
+ parsedArgs.Errors.Verify(Diagnostic(ERRID.ERR_ArgumentRequired).WithArguments("keyfile", ":").WithLocation(1, 1))
+ End Sub
+
Public Sub CommandLineMisc()
Dim args As VisualBasicCommandLineArguments
diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb
index 872d19825ca636c0fb6e3285a55e2b087d5c2a7c..57e576684048394e74b35cacec2149b7bfc5fca0 100644
--- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb
+++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb
@@ -34,6 +34,29 @@ BC37257: Option 'CryptoKeyFile' must be an absolute path.
)
End Sub
+
+
+ Public Sub PublicSignWithEmptyKeyPath()
+ Dim options = New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary).
+ WithPublicSign(True).WithCryptoKeyFile("")
+ AssertTheseDiagnostics(VisualBasicCompilation.Create("test", options:=options),
+
+BC37254: Public sign was specified and requires a public key, but no public key was specified
+)
+ End Sub
+
+
+
+ Public Sub PublicSignWithEmptyKeyPath2()
+ Dim options = New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary).
+ WithPublicSign(True).WithCryptoKeyFile("""""")
+ AssertTheseDiagnostics(VisualBasicCompilation.Create("test", options:=options),
+
+BC37254: Public sign was specified and requires a public key, but no public key was specified
+BC37257: Option 'CryptoKeyFile' must be an absolute path.
+)
+ End Sub
+
Public Sub LocalizableErrorArgumentToStringDoesntStackOverflow()
' Error ID is arbitrary
diff --git a/src/EditorFeatures/TestUtilities/ServicesTestUtilities.csproj b/src/EditorFeatures/TestUtilities/ServicesTestUtilities.csproj
index 0c3f3b985432fe6e0982420f6fa188bc258c65f5..e8971d13ee2e92d715de91ed3dccd937ae616bba 100644
--- a/src/EditorFeatures/TestUtilities/ServicesTestUtilities.csproj
+++ b/src/EditorFeatures/TestUtilities/ServicesTestUtilities.csproj
@@ -114,4 +114,7 @@
+
+
+
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
index ae810cd8c3caa65099a9f31b1727094db2d2a7d8..c0d0b830dd8a76a140a1605d44e610265c8819be 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
@@ -33,7 +33,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
using Workspace = Microsoft.CodeAnalysis.Workspace;
// NOTE: Microsoft.VisualStudio.LanguageServices.TypeScript.TypeScriptProject derives from AbstractProject.
+#pragma warning disable CS0618 // IVisualStudioHostProject is obsolete
internal abstract partial class AbstractProject : ForegroundThreadAffinitizedObject, IVisualStudioHostProject
+#pragma warning restore CS0618 // IVisualStudioHostProject is obsolete
{
internal static object RuleSetErrorId = new object();
private readonly object _gate = new object();
@@ -598,7 +600,7 @@ protected int AddMetadataReferenceAndTryConvertingToProjectReferenceIfPossible(s
// at this point, we don't know whether it is a metadata reference added because
// we don't have enough information yet for p2p reference or user explicitly added it
// as a metadata reference.
- AddMetadataReferenceCore(this.MetadataReferenceProvider.CreateMetadataReference(this, filePath, properties));
+ AddMetadataReferenceCore(this.MetadataReferenceProvider.CreateMetadataReference(filePath, properties));
// here, we change behavior compared to old C# language service. regardless of file being exist or not,
// we will always return S_OK. this is to support cross language p2p reference better.
@@ -1228,7 +1230,7 @@ internal void UndoProjectReferenceConversionForDisappearingOutputPath(string bin
projectReference.Aliases,
projectReference.EmbedInteropTypes);
- AddMetadataReferenceCore(MetadataReferenceProvider.CreateMetadataReference(this, binPath, metadataReferenceProperties));
+ AddMetadataReferenceCore(MetadataReferenceProvider.CreateMetadataReference(binPath, metadataReferenceProperties));
Contract.ThrowIfFalse(RemoveMetadataFileNameToConvertedProjectReference(binPath));
}
@@ -1255,7 +1257,7 @@ protected void UpdateMetadataReferenceAliases(string file, ImmutableArray
internal class DocumentKey : IEquatable
{
- private readonly IVisualStudioHostProject _hostProject;
+ private readonly AbstractProject _hostProject;
private readonly string _moniker;
- public IVisualStudioHostProject HostProject { get { return _hostProject; } }
+ public AbstractProject HostProject { get { return _hostProject; } }
public string Moniker { get { return _moniker; } }
- public DocumentKey(IVisualStudioHostProject hostProject, string moniker)
+ public DocumentKey(AbstractProject hostProject, string moniker)
{
Contract.ThrowIfNull(hostProject);
Contract.ThrowIfNull(moniker);
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs
index 8e3f3c9f90d644f3650ce0412561a29cb1d02120..9b9580a71415424628ab2e7e1dfd369710104a18 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs
@@ -26,7 +26,6 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
///
private readonly DocumentProvider _documentProvider;
private readonly string _itemMoniker;
- private readonly ITextUndoHistoryRegistry _textUndoHistoryRegistry;
private readonly FileChangeTracker _fileChangeTracker;
private readonly ReiteratedVersionSnapshotTracker _snapshotTracker;
private readonly TextLoader _doNotAccessDirectlyLoader;
@@ -38,7 +37,7 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
public DocumentId Id { get; }
public IReadOnlyList Folders { get; }
- public IVisualStudioHostProject Project { get; }
+ public AbstractProject Project { get; }
public SourceCodeKind SourceCodeKind { get; }
public DocumentKey Key { get; }
@@ -52,11 +51,10 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
///
public StandardTextDocument(
DocumentProvider documentProvider,
- IVisualStudioHostProject project,
+ AbstractProject project,
DocumentKey documentKey,
Func> getFolderNames,
SourceCodeKind sourceCodeKind,
- ITextUndoHistoryRegistry textUndoHistoryRegistry,
IVsFileChangeEx fileChangeService,
ITextBuffer openTextBuffer,
DocumentId id,
@@ -79,7 +77,6 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
this.Key = documentKey;
this.SourceCodeKind = sourceCodeKind;
- _textUndoHistoryRegistry = textUndoHistoryRegistry;
_fileChangeTracker = new FileChangeTracker(fileChangeService, this.FilePath);
_fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;
@@ -211,42 +208,20 @@ public void UpdateText(SourceText newText)
// expensive source control check if the file is already checked out.
if (_openTextBuffer != null)
{
- UpdateText(newText, _openTextBuffer, EditOptions.DefaultMinimalChange);
+ TextEditApplication.UpdateText(newText, _openTextBuffer, EditOptions.DefaultMinimalChange);
}
else
{
using (var invisibleEditor = ((VisualStudioWorkspaceImpl)this.Project.Workspace).OpenInvisibleEditor(this))
{
- UpdateText(newText, invisibleEditor.TextBuffer, EditOptions.None);
+ TextEditApplication.UpdateText(newText, invisibleEditor.TextBuffer, EditOptions.None);
}
}
}
- private static void UpdateText(SourceText newText, ITextBuffer buffer, EditOptions options)
+ public ITextBuffer GetTextUndoHistoryBuffer()
{
- using (var edit = buffer.CreateEdit(options, reiteratedVersionNumber: null, editTag: null))
- {
- var oldSnapshot = buffer.CurrentSnapshot;
- var oldText = oldSnapshot.AsText();
- var changes = newText.GetTextChanges(oldText);
- if (CodeAnalysis.Workspace.TryGetWorkspace(oldText.Container, out var workspace))
- {
- var undoService = workspace.Services.GetService();
- undoService.BeginUndoTransaction(oldSnapshot);
- }
-
- foreach (var change in changes)
- {
- edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
- }
-
- edit.ApplyAndLogExceptions();
- }
- }
-
- public ITextUndoHistory GetTextUndoHistory()
- {
- return _textUndoHistoryRegistry.GetHistory(GetOpenTextBuffer());
+ return GetOpenTextBuffer();
}
private string GetDebuggerDisplay()
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.cs
index 34bcbe1f9144ff72c36d20935fb2c3dae090a254..c850ded90711d95be96b027504adc10a027c93ae 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.cs
@@ -30,10 +30,9 @@ internal sealed partial class DocumentProvider : ForegroundThreadAffinitizedObje
#region Immutable readonly fields/properties that can be accessed from foreground or background threads - do not need locking for access.
private readonly object _gate = new object();
private readonly uint _runningDocumentTableEventCookie;
- private readonly IVisualStudioHostProjectContainer _projectContainer;
+ private readonly VisualStudioProjectTracker _projectTracker;
private readonly IVsFileChangeEx _fileChangeService;
private readonly IVsTextManager _textManager;
- private readonly ITextUndoHistoryRegistry _textUndoHistoryRegistry;
private readonly IVsRunningDocumentTable4 _runningDocumentTable;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly IContentTypeRegistryService _contentTypeRegistryService;
@@ -54,22 +53,20 @@ internal sealed partial class DocumentProvider : ForegroundThreadAffinitizedObje
///
/// Creates a document provider.
///
- /// Project container for the documents.
/// Service provider
/// An optional to track active and visible documents.
public DocumentProvider(
- IVisualStudioHostProjectContainer projectContainer,
+ VisualStudioProjectTracker projectTracker,
IServiceProvider serviceProvider,
VisualStudioDocumentTrackingService documentTrackingService)
{
var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
- _projectContainer = projectContainer;
+ _projectTracker = projectTracker;
this._documentTrackingServiceOpt = documentTrackingService;
this._runningDocumentTable = (IVsRunningDocumentTable4)serviceProvider.GetService(typeof(SVsRunningDocumentTable));
this._editorAdaptersFactoryService = componentModel.GetService();
this._contentTypeRegistryService = componentModel.GetService();
- _textUndoHistoryRegistry = componentModel.GetService();
_textManager = (IVsTextManager)serviceProvider.GetService(typeof(SVsTextManager));
_fileChangeService = (IVsFileChangeEx)serviceProvider.GetService(typeof(SVsFileChangeEx));
@@ -85,6 +82,28 @@ internal sealed partial class DocumentProvider : ForegroundThreadAffinitizedObje
Marshal.ThrowExceptionForHR(runningDocumentTableForEvents.AdviseRunningDocTableEvents(new RunningDocTableEventsSink(this), out _runningDocumentTableEventCookie));
}
+ [Obsolete("This overload is a compatibility shim for TypeScript; please do not use it.")]
+ public IVisualStudioHostDocument TryGetDocumentForFile(
+ IVisualStudioHostProject hostProject,
+ string filePath,
+ SourceCodeKind sourceCodeKind,
+ Func canUseTextBuffer,
+ Func> getFolderNames,
+ EventHandler updatedOnDiskHandler = null,
+ EventHandler openedHandler = null,
+ EventHandler closingHandler = null)
+ {
+ return TryGetDocumentForFile(
+ (AbstractProject)hostProject,
+ filePath,
+ sourceCodeKind,
+ canUseTextBuffer,
+ getFolderNames,
+ updatedOnDiskHandler,
+ openedHandler,
+ closingHandler);
+ }
+
///
/// Gets the for the file at the given filePath.
/// If we are on the foreground thread and this document is already open in the editor,
@@ -93,7 +112,7 @@ internal sealed partial class DocumentProvider : ForegroundThreadAffinitizedObje
/// whenever is invoked for the returned document.
///
public IVisualStudioHostDocument TryGetDocumentForFile(
- IVisualStudioHostProject hostProject,
+ AbstractProject hostProject,
string filePath,
SourceCodeKind sourceCodeKind,
Func canUseTextBuffer,
@@ -163,7 +182,6 @@ internal sealed partial class DocumentProvider : ForegroundThreadAffinitizedObje
documentKey,
getFolderNames,
sourceCodeKind,
- _textUndoHistoryRegistry,
_fileChangeService,
openTextBuffer,
id,
@@ -334,7 +352,7 @@ private void TryProcessOpenForDocCookie_NoLock(uint docCookie)
if (_runningDocumentTable.GetDocumentData(docCookie) is IVsTextBuffer shimTextBuffer)
{
var hasAssociatedRoslynDocument = false;
- foreach (var project in _projectContainer.GetProjects())
+ foreach (var project in _projectTracker.ImmutableProjects)
{
var documentKey = new DocumentKey(project, moniker);
@@ -391,11 +409,11 @@ private void TryProcessOpenForDocCookie_NoLock(uint docCookie)
{
// This is opening some other designer or property page. If it's tied to our IVsHierarchy, we should
// let the workspace know
- foreach (var project in _projectContainer.GetProjects())
+ foreach (var project in _projectTracker.ImmutableProjects)
{
if (hierarchy == project.Hierarchy)
{
- _projectContainer.NotifyNonDocumentOpenedForProject(project);
+ _projectTracker.NotifyNonDocumentOpenedForProject(project);
}
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostDocument.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostDocument.cs
index 6c54dc04524ce03b5ecc1f48dc6d0b8f882973a2..7689adb7c402949212a3a333897d1624d53de270 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostDocument.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostDocument.cs
@@ -22,7 +22,7 @@ internal interface IVisualStudioHostDocument : IDisposable
///
/// The visual studio project this document is part of.
///
- IVisualStudioHostProject Project { get; }
+ AbstractProject Project { get; }
///
/// The Visual Studio identity of the document within its project.
@@ -113,8 +113,8 @@ internal interface IVisualStudioHostDocument : IDisposable
void UpdateText(SourceText newText);
///
- /// Fetches the that should be used to undo edits to this document.
+ /// Fetches the that should be used to undo edits to this document.
///
- ITextUndoHistory GetTextUndoHistory();
+ ITextBuffer GetTextUndoHistoryBuffer();
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProject.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProject.cs
index 34e4f5621f7aaa885e5923616e837797cd0d9b32..5b86e708fd0f496459172bccfdd4f03de7dad014 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProject.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProject.cs
@@ -2,48 +2,15 @@
using System;
using Microsoft.CodeAnalysis;
-using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
///
- /// The interface implemented by all types of projects within Visual Studio (like regular
- /// projects, Miscellaneous files projects, etc.)
+ /// This interface only exists to maintain an overload of .
///
+ [Obsolete("This overload is a compatibility shim for TypeScript; please do not use it.")]
internal interface IVisualStudioHostProject
{
ProjectId Id { get; }
- string Language { get; }
-
- ///
- /// The for this project. NOTE: May be null in Deferred Project Load cases.
- ///
- IVsHierarchy Hierarchy { get; }
- Guid Guid { get; }
-
- Microsoft.CodeAnalysis.Workspace Workspace { get; }
-
- ///
- /// The public display name of the project. This name is not unique and may be shared
- /// between multiple projects, especially in cases like Venus where the intellisense
- /// projects will match the name of their logical parent project.
- ///
- string DisplayName { get; }
-
- ///
- /// The name of the project according to the project system. In "regular" projects this is
- /// equivalent to , but in Venus cases these will differ. The
- /// ProjectSystemName is the 2_Default.aspx project name, whereas the regular display name
- /// matches the display name of the project the user actually sees in the solution explorer.
- /// These can be assumed to be unique within the Visual Studio workspace.
- ///
- string ProjectSystemName { get; }
-
- IVisualStudioHostDocument GetDocumentOrAdditionalDocument(DocumentId id);
- IVisualStudioHostDocument GetCurrentDocumentFromPath(string filePath);
-
- ProjectInfo CreateProjectInfoForCurrentState();
-
- bool ContainsFile(string moniker);
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProjectContainer.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProjectContainer.cs
deleted file mode 100644
index ed1b129558a8da5f325ef6be35a7069e43ae5098..0000000000000000000000000000000000000000
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IVisualStudioHostProjectContainer.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.Collections.Generic;
-
-namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
-{
- ///
- /// An interface implemented by a workspace to get the set of host projects contained in the
- /// workspace.
- ///
- internal interface IVisualStudioHostProjectContainer
- {
- IReadOnlyList GetProjects();
-
- void NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project);
- }
-}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/InvisibleEditor.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/InvisibleEditor.cs
index 2f4728a5b20fe3b9748251768ee700b6eaf26b9d..deaf7be84b9642c22380c6c78d7bce080b9e42d4 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/InvisibleEditor.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/InvisibleEditor.cs
@@ -35,7 +35,7 @@ internal partial class InvisibleEditor : IInvisibleEditor
/// , which performs a much slower query of all
/// projects in the solution.
///
- public InvisibleEditor(IServiceProvider serviceProvider, string filePath, IVisualStudioHostProject projectOpt, bool needsSave, bool needsUndoDisabled)
+ public InvisibleEditor(IServiceProvider serviceProvider, string filePath, AbstractProject projectOpt, bool needsSave, bool needsUndoDisabled)
{
_serviceProvider = serviceProvider;
_filePath = filePath;
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/LinkedFileUtilities.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/LinkedFileUtilities.cs
index 43a024ca2a61966fb10fdb9a71eb43c865bd9c1b..6c72fce22c0f03e31e7b747f8bf516676834d8ec 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/LinkedFileUtilities.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/LinkedFileUtilities.cs
@@ -118,23 +118,23 @@ private IVsHierarchy GetSharedHierarchyForItemInternal(IVsHierarchy headProjectH
: null;
}
- public static IVisualStudioHostProject GetContextHostProject(IVsHierarchy sharedHierarchy, IVisualStudioHostProjectContainer hostProjectContainer)
+ public static AbstractProject GetContextHostProject(IVsHierarchy sharedHierarchy, VisualStudioProjectTracker projectTracker)
{
- return s_singleton.GetContextHostProjectInternal(sharedHierarchy, hostProjectContainer);
+ return s_singleton.GetContextHostProjectInternal(sharedHierarchy, projectTracker);
}
- private IVisualStudioHostProject GetContextHostProjectInternal(IVsHierarchy hierarchy, IVisualStudioHostProjectContainer hostProjectContainer)
+ private AbstractProject GetContextHostProjectInternal(IVsHierarchy hierarchy, VisualStudioProjectTracker projectTracker)
{
hierarchy = GetSharedItemContextHierarchy(hierarchy) ?? hierarchy;
var projectName = GetActiveIntellisenseProjectContextInternal(hierarchy);
if (projectName != null)
{
- return hostProjectContainer.GetProjects().FirstOrDefault(p => p.ProjectSystemName == projectName);
+ return projectTracker.ImmutableProjects.FirstOrDefault(p => p.ProjectSystemName == projectName);
}
else
{
- return hostProjectContainer.GetProjects().FirstOrDefault(p => p.Hierarchy == hierarchy);
+ return projectTracker.ImmutableProjects.FirstOrDefault(p => p.Hierarchy == hierarchy);
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs
index e23995c08940611fdfaa82f06752a8e4f56bce06..ef977368d234e3aa6c75eb8b884734fb3e76dd8c 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs
@@ -24,7 +24,7 @@ internal partial class VisualStudioMetadataReference
/// When the compilation is recreated for a solution the compiler asks for metadata again and we need to provide the original content,
/// not read the file again. Therefore we need to save the timestamp on the .
///
- /// When the VS observes a change in a metadata reference file the version is advanced and a new instance of
+ /// When the VS observes a change in a metadata reference file the project version is advanced and a new instance of
/// is created for the corresponding reference.
///
[DebuggerDisplay("{GetDebuggerDisplay(),nq}")]
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.cs
index 77cc71b5445f84a8e1422d1a838e0f21c81615e1..3a72d48300f953303bf5426c7154baa33633b237 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.cs
@@ -12,7 +12,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
internal sealed partial class VisualStudioMetadataReference : IDisposable
{
private readonly VisualStudioMetadataReferenceManager _provider;
- private readonly IVisualStudioHostProject _hostProject;
private readonly MetadataReferenceProperties _properties;
private readonly FileChangeTracker _fileChangeTracker;
@@ -22,14 +21,12 @@ internal sealed partial class VisualStudioMetadataReference : IDisposable
public VisualStudioMetadataReference(
VisualStudioMetadataReferenceManager provider,
- IVisualStudioHostProject hostProject,
string filePath,
MetadataReferenceProperties properties)
{
Contract.ThrowIfTrue(properties.Kind != MetadataImageKind.Assembly);
_provider = provider;
- _hostProject = hostProject;
_properties = properties;
// We don't track changes to netmodules linked to the assembly.
@@ -44,11 +41,6 @@ public string FilePath
get { return _fileChangeTracker.FilePath; }
}
- public IVisualStudioHostProject Project
- {
- get { return _hostProject; }
- }
-
public MetadataReferenceProperties Properties
{
get { return _properties; }
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs
index 4e2e149f4f021e08fdc74e5b3097c01f9bcc7199..367c87705b03345016f57b89a1e32536e4d6e42c 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs
@@ -86,9 +86,9 @@ public PortableExecutableReference CreateMetadataReferenceSnapshot(string filePa
return new VisualStudioMetadataReference.Snapshot(this, properties, filePath);
}
- public VisualStudioMetadataReference CreateMetadataReference(IVisualStudioHostProject hostProject, string filePath, MetadataReferenceProperties properties)
+ public VisualStudioMetadataReference CreateMetadataReference(string filePath, MetadataReferenceProperties properties)
{
- return new VisualStudioMetadataReference(this, hostProject, filePath, properties);
+ return new VisualStudioMetadataReference(this, filePath, properties);
}
public void ClearCache()
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.HostProject.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.HostProject.cs
deleted file mode 100644
index d34b414d574bc69ade401fb5190a41d62cf7b86d..0000000000000000000000000000000000000000
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.HostProject.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.Diagnostics;
-using EnvDTE;
-using Microsoft.CodeAnalysis;
-using Roslyn.Utilities;
-
-namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
-{
- using Workspace = Microsoft.CodeAnalysis.Workspace;
-
- internal partial class MiscellaneousFilesWorkspace
- {
- private sealed class HostProject : IVisualStudioHostProject
- {
- public ProjectId Id { get; }
- public string Language { get; }
-
- internal IVisualStudioHostDocument Document { get; set; }
-
- private readonly string _assemblyName;
- private readonly ParseOptions _parseOptionsOpt;
- private readonly CompilationOptions _compilationOptionsOpt;
- private readonly IEnumerable _metadataReferences;
- private readonly VersionStamp _version;
- private readonly Workspace _workspace;
-
- public HostProject(Workspace workspace, SolutionId solutionId, string languageName, ParseOptions parseOptionsOpt, CompilationOptions compilationOptionsOpt, IEnumerable metadataReferences)
- {
- Debug.Assert(workspace != null);
- Debug.Assert(languageName != null);
- Debug.Assert(metadataReferences != null);
-
- _workspace = workspace;
- _parseOptionsOpt = parseOptionsOpt;
- _compilationOptionsOpt = compilationOptionsOpt;
-
- Id = ProjectId.CreateNewId(debugName: "Miscellaneous Files");
- Language = languageName;
-
- // the assembly name must be unique for each collection of loose files. since the name doesn't matter
- // a random GUID can be used.
- _assemblyName = Guid.NewGuid().ToString("N");
-
- _version = VersionStamp.Create();
- _metadataReferences = metadataReferences;
- }
-
- public ProjectInfo CreateProjectInfoForCurrentState()
- {
- var info = ProjectInfo.Create(
- Id,
- _version,
- name: ServicesVSResources.Miscellaneous_Files,
- assemblyName: _assemblyName,
- language: Language,
- filePath: null,
- compilationOptions: _compilationOptionsOpt,
- parseOptions: _parseOptionsOpt,
- documents: SpecializedCollections.EmptyEnumerable(),
- projectReferences: SpecializedCollections.EmptyEnumerable(),
- metadataReferences: _metadataReferences,
- isSubmission: false,
- hostObjectType: null);
-
- // misc project will never be fully loaded since, by defintion, it won't know
- // what the full set of information is.
- return info.WithHasAllInformation(hasAllInformation: false);
- }
-
- public Microsoft.VisualStudio.Shell.Interop.IVsHierarchy Hierarchy => null;
-
- public Guid Guid => Guid.Empty;
-
- public string ProjectType => Constants.vsProjectKindMisc;
-
- public Workspace Workspace => _workspace;
-
- public string DisplayName => "MiscellaneousFiles";
- public string ProjectSystemName => DisplayName;
-
- public IVisualStudioHostDocument GetDocumentOrAdditionalDocument(DocumentId id)
- {
- if (id == this.Document.Id)
- {
- return this.Document;
- }
- else
- {
- return null;
- }
- }
-
- public IVisualStudioHostDocument GetCurrentDocumentFromPath(string filePath)
- {
- if (Document == null || !filePath.Equals(Document.Key.Moniker, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- return Document;
- }
-
- public bool ContainsFile(string moniker)
- {
- // We may have created our project but haven't created the document yet for it
- if (Document == null)
- {
- return false;
- }
-
- return moniker.Equals(Document.Key.Moniker, StringComparison.OrdinalIgnoreCase);
- }
- }
- }
-}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs
index 9fcf1f777eab85515a1b6fc0e2a7a1b76a365c4e..beb9f8f9d44e37f99f2ec3ed0a623169beffefc6 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs
@@ -17,6 +17,7 @@
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.TextManager.Interop;
using Roslyn.Utilities;
@@ -25,15 +26,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
using Workspace = Microsoft.CodeAnalysis.Workspace;
[Export(typeof(MiscellaneousFilesWorkspace))]
- internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IVsRunningDocTableEvents2, IVisualStudioHostProjectContainer
+ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IVsRunningDocTableEvents2
{
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly IMetadataAsSourceFileService _fileTrackingMetadataAsSourceService;
private readonly IVsRunningDocumentTable4 _runningDocumentTable;
private readonly IVsTextManager _textManager;
- private readonly DocumentProvider _documentProvider;
-
private readonly Dictionary _languageInformationByLanguageGuid = new Dictionary();
///
@@ -42,8 +41,11 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IVsRunnin
///
private IBidirectionalMap _docCookieToWorkspaceRegistration = BidirectionalMap.Empty;
- private readonly Dictionary _hostProjects = new Dictionary();
- private readonly Dictionary _docCookiesToHostProject = new Dictionary();
+ ///
+ /// The mapping of all doc cookies in the RDT and the of the project and of the open
+ /// file we have created for that open buffer. An entry should only be in here if it's also already in .
+ ///
+ private readonly Dictionary _docCookiesToProjectIdAndContainer = new Dictionary();
private readonly ImmutableArray _metadataReferences;
private uint _runningDocumentTableEventsCookie;
@@ -69,7 +71,6 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IVsRunnin
((IVsRunningDocumentTable)_runningDocumentTable).AdviseRunningDocTableEvents(this, out _runningDocumentTableEventsCookie);
_metadataReferences = ImmutableArray.CreateRange(CreateMetadataReferences());
- _documentProvider = new DocumentProvider(this, serviceProvider, documentTrackingService: null);
saveEventsService.StartSendingSaveEvents();
}
@@ -140,7 +141,7 @@ public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarch
{
var moniker = _runningDocumentTable.GetDocumentMoniker(docCookie);
- if (moniker != null && TryGetLanguageInformation(moniker) != null && !_docCookiesToHostProject.ContainsKey(docCookie))
+ if (moniker != null && TryGetLanguageInformation(moniker) != null && !_docCookiesToProjectIdAndContainer.ContainsKey(docCookie))
{
TrackOpenedDocument(docCookie, moniker);
}
@@ -256,15 +257,12 @@ private void Registration_WorkspaceChanged(object sender, EventArgs e)
if (workspaceRegistration.Workspace == null)
{
- if (_docCookiesToHostProject.TryGetValue(docCookie, out var hostProject))
+ if (_docCookiesToProjectIdAndContainer.TryGetValue(docCookie, out var projectIdAndSourceTextContainer))
{
// The workspace was taken from us and released and we have only asynchronously found out now.
- var document = hostProject.Document;
-
- if (document.IsOpen)
- {
- RegisterText(document.GetOpenTextContainer());
- }
+ // We already have the file open in our workspace, but the global mapping of source text container
+ // to the workspace that owns it needs to be updated once more.
+ RegisterText(projectIdAndSourceTextContainer.textContainer);
}
else
{
@@ -281,7 +279,7 @@ private void Registration_WorkspaceChanged(object sender, EventArgs e)
else if (IsClaimedByAnotherWorkspace(workspaceRegistration))
{
// It's now claimed by another workspace, so we should unclaim it
- if (_docCookiesToHostProject.ContainsKey(docCookie))
+ if (_docCookiesToProjectIdAndContainer.ContainsKey(docCookie))
{
DetachFromDocument(docCookie, moniker);
}
@@ -330,17 +328,32 @@ private void AttachToDocument(uint docCookie, string moniker)
return;
}
+ var projectInfo = CreateProjectInfoForDocument(moniker);
+
+ OnProjectAdded(projectInfo);
+
+ var sourceTextContainer = textBuffer.AsTextContainer();
+ OnDocumentOpened(projectInfo.Documents.Single().Id, sourceTextContainer);
+
+ _docCookiesToProjectIdAndContainer.Add(docCookie, (projectInfo.Id, sourceTextContainer));
+ }
+
+ ///
+ /// Creates the that can be added to the workspace for a newly opened document.
+ ///
+ private ProjectInfo CreateProjectInfoForDocument(string filePath)
+ {
// This should always succeed since we only got here if we already confirmed the moniker is acceptable
- var languageInformation = TryGetLanguageInformation(moniker);
+ var languageInformation = TryGetLanguageInformation(filePath);
Contract.ThrowIfNull(languageInformation);
var languageServices = Services.GetLanguageServices(languageInformation.LanguageName);
var compilationOptionsOpt = languageServices.GetService()?.GetDefaultCompilationOptions();
var parseOptionsOpt = languageServices.GetService()?.GetDefaultParseOptions();
- if (parseOptionsOpt != null &&
+ if (parseOptionsOpt != null &&
compilationOptionsOpt != null &&
- PathUtilities.GetExtension(moniker) == languageInformation.ScriptExtension)
+ PathUtilities.GetExtension(filePath) == languageInformation.ScriptExtension)
{
parseOptionsOpt = parseOptionsOpt.WithKind(SourceCodeKind.Script);
@@ -350,7 +363,7 @@ private void AttachToDocument(uint docCookie, string moniker)
// Misc files workspace always provides the service:
Contract.ThrowIfNull(scriptEnvironmentService);
- var baseDirectory = PathUtilities.GetDirectoryName(moniker);
+ var baseDirectory = PathUtilities.GetDirectoryName(filePath);
// TODO (https://github.com/dotnet/roslyn/issues/5325, https://github.com/dotnet/roslyn/issues/13886):
// - Need to have a way to specify these somewhere in VS options.
@@ -367,40 +380,34 @@ private void AttachToDocument(uint docCookie, string moniker)
WithSourceReferenceResolver(new SourceFileResolver(scriptEnvironmentService.SourceReferenceSearchPaths, baseDirectory));
}
- // First, create the project
- var hostProject = new HostProject(this, CurrentSolution.Id, languageInformation.LanguageName, parseOptionsOpt, compilationOptionsOpt, _metadataReferences);
-
- // Now try to find the document. We accept any text buffer, since we've already verified it's an appropriate file in ShouldIncludeFile.
- var document = _documentProvider.TryGetDocumentForFile(
- hostProject,
- moniker,
- parseOptionsOpt?.Kind ?? SourceCodeKind.Regular,
- getFolderNames: _ => SpecializedCollections.EmptyReadOnlyList(),
- canUseTextBuffer: _ => true);
-
- // If the buffer has not yet been initialized, we won't get a document.
- if (document == null)
- {
- return;
- }
-
- // Since we have a document, we can do the rest of the project setup.
- _hostProjects.Add(hostProject.Id, hostProject);
- OnProjectAdded(hostProject.CreateProjectInfoForCurrentState());
-
- OnDocumentAdded(document.GetInitialState());
- hostProject.Document = document;
-
- // Notify the document provider, so it knows the document is now open and a part of
- // the project
- _documentProvider.NotifyDocumentRegisteredToProjectAndStartToRaiseEvents(document);
-
- Contract.ThrowIfFalse(document.IsOpen);
-
- var buffer = document.GetOpenTextBuffer();
- OnDocumentOpened(document.Id, document.GetOpenTextContainer());
-
- _docCookiesToHostProject.Add(docCookie, hostProject);
+ var projectId = ProjectId.CreateNewId(debugName: "Miscellaneous Files Project for " + filePath);
+ var documentId = DocumentId.CreateNewId(projectId, debugName: filePath);
+
+ var documentInfo = DocumentInfo.Create(
+ documentId,
+ filePath,
+ sourceCodeKind: parseOptionsOpt?.Kind ?? SourceCodeKind.Regular,
+ loader: new FileTextLoader(filePath, defaultEncoding: null),
+ filePath: filePath);
+
+ // The assembly name must be unique for each collection of loose files. Since the name doesn't matter
+ // a random GUID can be used.
+ string assemblyName = Guid.NewGuid().ToString("N");
+
+ var projectInfo = ProjectInfo.Create(
+ projectId,
+ VersionStamp.Create(),
+ name: ServicesVSResources.Miscellaneous_Files,
+ assemblyName,
+ languageInformation.LanguageName,
+ compilationOptions: compilationOptionsOpt,
+ parseOptions: parseOptionsOpt,
+ documents: SpecializedCollections.SingletonEnumerable(documentInfo),
+ metadataReferences: _metadataReferences);
+
+ // Miscellaneous files projects are never fully loaded since, by definition, it won't know
+ // what the full set of information is.
+ return projectInfo.WithHasAllInformation(hasAllInformation: false);
}
private void DetachFromDocument(uint docCookie, string moniker)
@@ -411,18 +418,15 @@ private void DetachFromDocument(uint docCookie, string moniker)
return;
}
- if (_docCookiesToHostProject.TryGetValue(docCookie, out var hostProject))
+ if (_docCookiesToProjectIdAndContainer.TryGetValue(docCookie, out var projectIdAndContainer))
{
- var document = hostProject.Document;
-
- OnDocumentClosed(document.Id, document.Loader);
- OnDocumentRemoved(document.Id);
- OnProjectRemoved(hostProject.Id);
+ var document = this.CurrentSolution.GetProject(projectIdAndContainer.projectId).Documents.Single();
- _hostProjects.Remove(hostProject.Id);
- _docCookiesToHostProject.Remove(docCookie);
+ // We must close the document prior to deleting the project
+ OnDocumentClosed(document.Id, new FileTextLoader(document.FilePath, defaultEncoding: null));
+ OnProjectRemoved(document.Project.Id);
- document.Dispose();
+ _docCookiesToProjectIdAndContainer.Remove(docCookie);
return;
}
@@ -452,35 +456,14 @@ public override bool CanApplyChange(ApplyChangesKind feature)
protected override void ApplyDocumentTextChanged(DocumentId documentId, SourceText newText)
{
- var hostDocument = this.GetDocument(documentId);
- hostDocument.UpdateText(newText);
- }
-
- private HostProject GetHostProject(ProjectId id)
- {
- _hostProjects.TryGetValue(id, out var project);
- return project;
- }
-
- internal IVisualStudioHostDocument GetDocument(DocumentId id)
- {
- var project = GetHostProject(id.ProjectId);
- if (project != null && project.Document.Id == id)
+ foreach (var projectIdAndSourceTextContainer in _docCookiesToProjectIdAndContainer.Values)
{
- return project.Document;
+ if (projectIdAndSourceTextContainer.projectId == documentId.ProjectId)
+ {
+ TextEditApplication.UpdateText(newText, projectIdAndSourceTextContainer.textContainer.GetTextBuffer(), EditOptions.DefaultMinimalChange);
+ break;
+ }
}
-
- return null;
- }
-
- IReadOnlyList IVisualStudioHostProjectContainer.GetProjects()
- {
- return _hostProjects.Values.ToImmutableReadOnlyListOrEmpty();
- }
-
- void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
- {
- // Since the MiscellaneousFilesWorkspace doesn't do anything lazily, this is a no-op
}
private class LanguageInformation
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/TextEditApplication.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/TextEditApplication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e4e64a3d343a14d5f78d60fabc9434a2ab76ee7
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/TextEditApplication.cs
@@ -0,0 +1,32 @@
+using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
+using Microsoft.CodeAnalysis.Editor.Undo;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.VisualStudio.Text;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+{
+ internal static class TextEditApplication
+ {
+ internal static void UpdateText(SourceText newText, ITextBuffer buffer, EditOptions options)
+ {
+ using (var edit = buffer.CreateEdit(options, reiteratedVersionNumber: null, editTag: null))
+ {
+ var oldSnapshot = buffer.CurrentSnapshot;
+ var oldText = oldSnapshot.AsText();
+ var changes = newText.GetTextChanges(oldText);
+ if (CodeAnalysis.Workspace.TryGetWorkspace(oldText.Container, out var workspace))
+ {
+ var undoService = workspace.Services.GetService();
+ undoService.BeginUndoTransaction(oldSnapshot);
+ }
+
+ foreach (var change in changes)
+ {
+ edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
+ }
+
+ edit.ApplyAndLogExceptions();
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs
index 85e3d1130d65b43dab4c5c92288e873b7dc3c844..0fca1b9997faa41c7102635f030199be50a32de9 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs
@@ -17,7 +17,7 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
- internal sealed partial class VisualStudioProjectTracker : ForegroundThreadAffinitizedObject, IVisualStudioHostProjectContainer
+ internal sealed partial class VisualStudioProjectTracker : ForegroundThreadAffinitizedObject
{
#region Readonly fields
private static readonly ConditionalWeakTable s_workingFolderPathMap = new ConditionalWeakTable();
@@ -92,9 +92,7 @@ internal ImmutableArray ImmutableProjects
internal HostWorkspaceServices WorkspaceServices { get; }
- IReadOnlyList IVisualStudioHostProjectContainer.GetProjects() => this.ImmutableProjects;
-
- void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisualStudioHostProject project)
+ internal void NotifyNonDocumentOpenedForProject(AbstractProject project)
{
AssertIsForeground();
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
index 471df955dce903adb89bdb183dfffd38ca7a6d02..f08f586d5f20ba8881186c56f8104c4d2fb42dda 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
@@ -108,12 +108,12 @@ internal IVisualStudioHostDocument GetHostDocument(DocumentId documentId)
return null;
}
- internal IVisualStudioHostProject GetHostProject(ProjectId projectId)
+ internal AbstractProject GetHostProject(ProjectId projectId)
{
return DeferredState?.ProjectTracker.GetProject(projectId);
}
- private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject project)
+ private bool TryGetHostProject(ProjectId projectId, out AbstractProject project)
{
project = GetHostProject(projectId);
return project != null;
@@ -241,7 +241,7 @@ public override bool CanApplyChange(ApplyChangesKind feature)
}
}
- private bool TryGetProjectData(ProjectId projectId, out IVisualStudioHostProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
+ private bool TryGetProjectData(ProjectId projectId, out AbstractProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
{
hierarchy = null;
project = null;
@@ -251,7 +251,7 @@ private bool TryGetProjectData(ProjectId projectId, out IVisualStudioHostProject
&& hierarchy.TryGetProject(out project);
}
- internal void GetProjectData(ProjectId projectId, out IVisualStudioHostProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
+ internal void GetProjectData(ProjectId projectId, out AbstractProject hostProject, out IVsHierarchy hierarchy, out EnvDTE.Project project)
{
if (!TryGetProjectData(projectId, out hostProject, out hierarchy, out project))
{
@@ -622,7 +622,7 @@ protected override void AddExistingDocument(DocumentId documentId, string filePa
#endif
private ProjectItem AddDocumentToProject(
- IVisualStudioHostProject hostProject,
+ AbstractProject hostProject,
EnvDTE.Project project,
DocumentId documentId,
string documentName,
@@ -641,7 +641,7 @@ protected override void AddExistingDocument(DocumentId documentId, string filePa
}
private ProjectItem AddDocumentToFolder(
- IVisualStudioHostProject hostProject,
+ AbstractProject hostProject,
EnvDTE.Project project,
DocumentId documentId,
IEnumerable folders,
@@ -662,7 +662,7 @@ protected override void AddExistingDocument(DocumentId documentId, string filePa
}
private ProjectItem AddDocumentToProjectItems(
- IVisualStudioHostProject hostProject,
+ AbstractProject hostProject,
ProjectItems projectItems,
DocumentId documentId,
string folderPath,
@@ -865,7 +865,7 @@ protected override void ApplyAdditionalDocumentTextChanged(DocumentId documentId
hostDocument.UpdateText(newText);
}
- private static string GetPreferredExtension(IVisualStudioHostProject hostProject, SourceCodeKind sourceCodeKind)
+ private static string GetPreferredExtension(AbstractProject hostProject, SourceCodeKind sourceCodeKind)
{
// No extension was provided. Pick a good one based on the type of host project.
switch (hostProject.Language)
diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
index 06462360b86ba9b9c909596f15dda13e48ca8b17..8dd9bad0ceeb4943061a65c50fb369809201e057 100644
--- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
@@ -181,8 +181,6 @@ public bool IsOpen
#pragma warning restore 67
- IVisualStudioHostProject IVisualStudioHostDocument.Project { get { return this.Project; } }
-
public ITextBuffer GetOpenTextBuffer()
{
return _containedLanguage.SubjectBuffer;
@@ -1150,10 +1148,10 @@ private bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag
return CheckCode(snapshot, position - tag2.Length, tag1);
}
- public ITextUndoHistory GetTextUndoHistory()
+ public ITextBuffer GetTextUndoHistoryBuffer()
{
// In Venus scenarios, the undo history is associated with the data buffer
- return _componentModel.GetService().GetHistory(_containedLanguage.DataBuffer);
+ return _containedLanguage.DataBuffer;
}
public uint GetItemId()
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioTextUndoHistoryWorkspaceServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioTextUndoHistoryWorkspaceServiceFactory.cs
index 62050cb5c4e4f2188871ee507b8b0bf7d170f3ee..344f7940781bb962e5b77a120dc2af5f8d4320e3 100644
--- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioTextUndoHistoryWorkspaceServiceFactory.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioTextUndoHistoryWorkspaceServiceFactory.cs
@@ -1,11 +1,6 @@
// 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.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host;
@@ -25,9 +20,9 @@ internal class VisualStudioTextUndoHistoryWorkspaceServiceFactory : IWorkspaceSe
private readonly ITextUndoHistoryWorkspaceService _serviceSingleton;
[ImportingConstructor]
- public VisualStudioTextUndoHistoryWorkspaceServiceFactory()
+ public VisualStudioTextUndoHistoryWorkspaceServiceFactory(ITextUndoHistoryRegistry undoHistoryRegistry)
{
- _serviceSingleton = new TextUndoHistoryWorkspaceService();
+ _serviceSingleton = new TextUndoHistoryWorkspaceService(undoHistoryRegistry);
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
@@ -37,44 +32,48 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
private class TextUndoHistoryWorkspaceService : ITextUndoHistoryWorkspaceService
{
- public bool TryGetTextUndoHistory(Workspace editorWorkspace, ITextBuffer textBuffer, out ITextUndoHistory undoHistory)
+ private ITextUndoHistoryRegistry _undoHistoryRegistry;
+
+ public TextUndoHistoryWorkspaceService(ITextUndoHistoryRegistry undoHistoryRegistry)
{
- undoHistory = null;
+ _undoHistoryRegistry = undoHistoryRegistry;
+ }
- if (!(editorWorkspace is VisualStudioWorkspaceImpl) &&
- !(editorWorkspace is MiscellaneousFilesWorkspace))
+ public bool TryGetTextUndoHistory(Workspace editorWorkspace, ITextBuffer textBuffer, out ITextUndoHistory undoHistory)
+ {
+ switch (editorWorkspace)
{
- return false;
- }
+ case VisualStudioWorkspaceImpl visualStudioWorkspace:
- // TODO: Handle undo if context changes
- var documentId = editorWorkspace.GetDocumentIdInCurrentContext(textBuffer.AsTextContainer());
- if (documentId == null)
- {
- return false;
- }
+ // TODO: Handle undo if context changes
+ var documentId = editorWorkspace.GetDocumentIdInCurrentContext(textBuffer.AsTextContainer());
+ if (documentId == null)
+ {
+ undoHistory = null;
+ return false;
+ }
- var document = GetDocument(editorWorkspace, documentId);
- if (document == null)
- {
- return false;
- }
+ // In the Visual Studio case, there might be projection buffers involved for Venus,
+ // where we associate undo history with the surface buffer and not the subject buffer.
+ textBuffer = visualStudioWorkspace.GetHostDocument(documentId).GetTextUndoHistoryBuffer();
- undoHistory = document.GetTextUndoHistory();
- return true;
- }
+ break;
+
+ case MiscellaneousFilesWorkspace miscellaneousFilesWorkspace:
+
+ // Nothing to do in this case: textBuffer is correct!
+
+ break;
+
+ default:
+
+ undoHistory = null;
+ return false;
- private IVisualStudioHostDocument GetDocument(Workspace workspace, DocumentId id)
- {
- switch (workspace)
- {
- case VisualStudioWorkspaceImpl visualStudioWorkspace:
- return visualStudioWorkspace.GetHostDocument(id);
- case MiscellaneousFilesWorkspace miscWorkspace:
- return miscWorkspace.GetDocument(id);
}
- return null;
+ undoHistory = _undoHistoryRegistry.GetHistory(textBuffer);
+ return true;
}
}
}
diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb
index 2f2c8c42eff3d6b76e2fb31b69868d06ba00dd43..a0c2e56289dff11203b29d3976df53a5ab3dd7e7 100644
--- a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb
+++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProject.vb
@@ -19,7 +19,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim
Partial Friend MustInherit Class VisualBasicProject
Inherits AbstractLegacyProject
Implements IVbCompilerProject
- Implements IVisualStudioHostProject
Private ReadOnly _compilerHost As IVbCompilerHost
Private ReadOnly _imports As New List(Of GlobalImport)