diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 8fa4682670cb4..4282d9364c4b7 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -8496,6 +8496,21 @@ public void Namespace_Insert_NewType_Qualified(string src2) capabilities: EditAndContinueCapabilities.NewTypeDefinition); } + [Fact] + public void Namespace_Insert_NewType_HidingMetadataType() + { + var srcA1 = ""; + var srcA2 = """ + namespace Microsoft.CodeAnalysis; + public readonly partial class EmbeddedAttribute; + """; + + EditAndContinueValidation.VerifySemantics( + GetTopEdits(srcA1, srcA2), + [SemanticEdit(SemanticEditKind.Insert, c => c.Assembly.GlobalNamespace.GetMember("Microsoft").GetMember("CodeAnalysis").GetMember("EmbeddedAttribute"))], + capabilities: EditAndContinueCapabilities.NewTypeDefinition); + } + [Theory] [InlineData("class")] [InlineData("interface")] @@ -8759,7 +8774,12 @@ public void Namespace_Update_FileScoped() [Fact] public void Namespace_Update_MultiplePartials1() => EditAndContinueValidation.VerifySemantics( - [GetTopEdits(@"namespace N { partial class/*1*/C {} } namespace N { partial class/*2*/C {} }", @"namespace N { partial class/*1*/C {} } namespace M { partial class/*2*/C {} }"), GetTopEdits(@"namespace N { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }", @"namespace M { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }")], + [GetTopEdits( + @"namespace N { partial class/*1*/C {} } namespace N { partial class/*2*/C {} }", + @"namespace N { partial class/*1*/C {} } namespace M { partial class/*2*/C {} }"), + GetTopEdits( + @"namespace N { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }", + @"namespace M { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }")], [ DocumentResults( semanticEdits: @@ -8777,7 +8797,12 @@ public void Namespace_Update_MultiplePartials1() [Fact] public void Namespace_Update_MultiplePartials2() => EditAndContinueValidation.VerifySemantics( - [GetTopEdits(@"namespace N { partial class/*1*/C {} } namespace N { partial class/*2*/C {} }", @"namespace M { partial class/*1*/C {} } namespace M { partial class/*2*/C {} }"), GetTopEdits(@"namespace N { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }", @"namespace M { partial class/*3*/C {} } namespace M { partial class/*4*/C {} }")], + [GetTopEdits( + @"namespace N { partial class/*1*/C {} } namespace N { partial class/*2*/C {} }", + @"namespace M { partial class/*1*/C {} } namespace M { partial class/*2*/C {} }"), + GetTopEdits( + @"namespace N { partial class/*3*/C {} } namespace N { partial class/*4*/C {} }", + @"namespace M { partial class/*3*/C {} } namespace M { partial class/*4*/C {} }")], [ DocumentResults(diagnostics: [ diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 7e765c700fd9c..d781f651a7624 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2754,8 +2754,8 @@ private async Task> AnalyzeSemanticsAsync( continue; } - var oldSymbolInNewCompilation = symbolCache.GetKey(oldSymbol, cancellationToken).Resolve(newModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; - var newSymbolInOldCompilation = symbolCache.GetKey(newSymbol, cancellationToken).Resolve(oldModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var oldSymbolInNewCompilation = symbolCache.GetKey(oldSymbol, cancellationToken).Resolve(newModel.Compilation, cancellationToken: cancellationToken).Symbol; + var newSymbolInOldCompilation = symbolCache.GetKey(newSymbol, cancellationToken).Resolve(oldModel.Compilation, cancellationToken: cancellationToken).Symbol; if (oldSymbolInNewCompilation == null || newSymbolInOldCompilation == null) { @@ -2823,8 +2823,8 @@ private async Task> AnalyzeSemanticsAsync( if (containingType != null && (syntacticEditKind != EditKind.Delete || newSymbol == null)) { var containingTypeSymbolKey = symbolCache.GetKey(containingType, cancellationToken); - oldContainingType ??= (INamedTypeSymbol?)containingTypeSymbolKey.Resolve(oldModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; - newContainingType ??= (INamedTypeSymbol?)containingTypeSymbolKey.Resolve(newModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + oldContainingType ??= (INamedTypeSymbol?)containingTypeSymbolKey.Resolve(oldModel.Compilation, cancellationToken: cancellationToken).Symbol; + newContainingType ??= (INamedTypeSymbol?)containingTypeSymbolKey.Resolve(newModel.Compilation, cancellationToken: cancellationToken).Symbol; if (oldContainingType != null && newContainingType != null && IsReloadable(oldContainingType)) { @@ -2967,7 +2967,7 @@ newSymbol is IPropertySymbol newProperty && // If so, skip the member deletion and only report the containing symbol deletion. var oldContainingType = oldSymbol.ContainingType; var containingTypeKey = symbolCache.GetKey(oldContainingType, cancellationToken); - var newContainingType = (INamedTypeSymbol?)containingTypeKey.Resolve(newModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var newContainingType = (INamedTypeSymbol?)containingTypeKey.Resolve(newModel.Compilation, cancellationToken: cancellationToken).Symbol; if (newContainingType == null) { // If a type parameter is deleted from the parameter list of a type declaration, the symbol key won't be resolved (because the arities do not match). @@ -3092,7 +3092,7 @@ newSymbol is IPropertySymbol newProperty && HasEdit(editMap, GetSymbolDeclarationSyntax(newAssociatedMember, cancellationToken), EditKind.Insert); var containingTypeKey = symbolCache.GetKey(newContainingType, cancellationToken); - oldContainingType = containingTypeKey.Resolve(oldModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol as INamedTypeSymbol; + oldContainingType = containingTypeKey.Resolve(oldModel.Compilation, cancellationToken: cancellationToken).Symbol as INamedTypeSymbol; // Check rude edits for each member even if it is inserted into a new type. if (!hasAssociatedSymbolInsert && IsMember(newSymbol)) @@ -3629,7 +3629,7 @@ bool PreprocessSymbolEdit(ref ISymbol? oldSymbol, ref ISymbol? newSymbol) static ISymbol? Resolve(ISymbol symbol, SymbolKey symbolKey, Compilation compilation, CancellationToken cancellationToken) { // Ignore ambiguous resolution result - it may happen if there are semantic errors in the compilation. - var result = symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var result = symbolKey.Resolve(compilation, cancellationToken: cancellationToken).Symbol; // If we were looking for a definition and an implementation is returned the definition does not exist. return symbol.IsPartialImplementation() && result?.IsPartialDefinition() == true ? null : result; @@ -3709,7 +3709,7 @@ protected static bool IsMemberOrDelegate(ISymbol symbol) protected static ISymbol? GetSemanticallyMatchingNewSymbol(ISymbol? oldSymbol, ISymbol? newSymbol, Compilation newCompilation, SymbolInfoCache symbolCache, CancellationToken cancellationToken) => oldSymbol != null && IsMember(oldSymbol) && newSymbol != null && IsMember(newSymbol) && - symbolCache.GetKey(oldSymbol, cancellationToken).Resolve(newCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol is { } matchingNewSymbol && + symbolCache.GetKey(oldSymbol, cancellationToken).Resolve(newCompilation, cancellationToken: cancellationToken).Symbol is { } matchingNewSymbol && !matchingNewSymbol.IsSynthesized() && matchingNewSymbol != newSymbol ? matchingNewSymbol @@ -3805,7 +3805,7 @@ void AddEdits(IMethodSymbol? constructor, Compilation otherCompilation, bool isD IsPrimaryConstructor(constructor, cancellationToken) && constructor.GetMatchingDeconstructor() is { IsImplicitlyDeclared: true } deconstructor) { - if (SymbolKey.Create(deconstructor, cancellationToken).Resolve(otherCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol != null) + if (SymbolKey.Create(deconstructor, cancellationToken).Resolve(otherCompilation, cancellationToken: cancellationToken).Symbol != null) { // Update for transition from synthesized to declared deconstructor AddUpdateEditsForMemberAndAccessors(semanticEdits, deconstructor, cancellationToken); @@ -4053,7 +4053,7 @@ void AddDelete(ISymbol? symbol) continue; } - var newType = SymbolKey.Create(oldType, cancellationToken).Resolve(newModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var newType = SymbolKey.Create(oldType, cancellationToken).Resolve(newModel.Compilation, cancellationToken: cancellationToken).Symbol; if (newType == null) { var key = (oldType.Name, oldType.Arity); @@ -4084,7 +4084,7 @@ void AddDelete(ISymbol? symbol) continue; } - var oldType = SymbolKey.Create(newType, cancellationToken).Resolve(oldModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var oldType = SymbolKey.Create(newType, cancellationToken).Resolve(oldModel.Compilation, cancellationToken: cancellationToken).Symbol; if (oldType == null) { // Check if a type with the same name and arity was also removed. If so treat it as a move. @@ -5193,7 +5193,7 @@ private SyntaxNode GetDiagnosticNode(out int distance, CancellationToken cancell while (oldContainer is not null and not INamespaceSymbol { IsGlobalNamespace: true }) { var symbolKey = SymbolKey.Create(oldSymbol, cancellationToken); - if (symbolKey.Resolve(newModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol is { } newSymbol) + if (symbolKey.Resolve(newModel.Compilation, cancellationToken: cancellationToken).Symbol is { } newSymbol) { return newSymbol; } @@ -5600,7 +5600,7 @@ private void AddConstructorEdits( } else { - var resolution = newCtorKey.Resolve(oldModel.Compilation, ignoreAssemblyKey: true, cancellationToken); + var resolution = newCtorKey.Resolve(oldModel.Compilation, cancellationToken: cancellationToken); // There may be semantic errors in the compilation that result in multiple candidates. // Pick the first candidate. @@ -7054,7 +7054,7 @@ private bool DeleteEditImpliesInsertEdit(ISymbol oldSymbol, ISymbol newSymbol, C GetPrimaryConstructor(newSymbol.ContainingType, cancellationToken) is { } newPrimaryConstructor && method.HasDeconstructorSignature(newPrimaryConstructor)) { - var oldConstructor = SymbolKey.Create(newPrimaryConstructor, cancellationToken).Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var oldConstructor = SymbolKey.Create(newPrimaryConstructor, cancellationToken).Resolve(oldCompilation, cancellationToken: cancellationToken).Symbol; // An insert exists if the new primary constructor is explicitly declared and // the old one doesn't exist, is synthesized, or is not a primary constructor parameter. @@ -7067,7 +7067,7 @@ private bool DeleteEditImpliesInsertEdit(ISymbol oldSymbol, ISymbol newSymbol, C GetPrimaryConstructor(newSymbol.ContainingType, cancellationToken)?.Parameters.FirstOrDefault( static (parameter, name) => parameter.Name == name, newSymbol.Name) is { } newPrimaryParameter) { - var oldParameter = SymbolKey.Create(newPrimaryParameter, cancellationToken).Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol; + var oldParameter = SymbolKey.Create(newPrimaryParameter, cancellationToken).Resolve(oldCompilation, cancellationToken: cancellationToken).Symbol; var oldProperty = (IPropertySymbol)oldSymbol; // An insert exists if the new primary parameter is explicitly declared and diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 46f4185b7bb67..bc72391f66cb7 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -841,7 +841,7 @@ internal static void MergePartialEdits( SymbolKeyResolution oldResolution; if (edit.Kind is SemanticEditKind.Update or SemanticEditKind.Delete) { - oldResolution = edit.Symbol.Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken); + oldResolution = edit.Symbol.Resolve(oldCompilation, cancellationToken: cancellationToken); Contract.ThrowIfNull(oldResolution.Symbol); } else @@ -852,13 +852,13 @@ internal static void MergePartialEdits( SymbolKeyResolution newResolution; if (edit.Kind is SemanticEditKind.Update or SemanticEditKind.Insert or SemanticEditKind.Replace) { - newResolution = edit.Symbol.Resolve(newCompilation, ignoreAssemblyKey: true, cancellationToken); + newResolution = edit.Symbol.Resolve(newCompilation, cancellationToken: cancellationToken); Contract.ThrowIfNull(newResolution.Symbol); } else if (edit.Kind == SemanticEditKind.Delete && edit.DeletedSymbolContainer is not null) { // For deletes, we use NewSymbol to reference the containing type of the deleted member - newResolution = edit.DeletedSymbolContainer.Value.Resolve(newCompilation, ignoreAssemblyKey: true, cancellationToken); + newResolution = edit.DeletedSymbolContainer.Value.Resolve(newCompilation, cancellationToken: cancellationToken); Contract.ThrowIfNull(newResolution.Symbol); } else diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs index ff7599a006889..068aec2a6ff6d 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs @@ -342,8 +342,8 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) expectedOldSymbol = expectedSemanticEdit.SymbolProvider(oldCompilation); expectedNewSymbol = expectedSemanticEdit.SymbolProvider(newCompilation); - Assert.Equal(expectedOldSymbol, symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol); - Assert.Equal(expectedNewSymbol, symbolKey.Resolve(newCompilation, ignoreAssemblyKey: true).Symbol); + Assert.Equal(expectedOldSymbol, symbolKey.Resolve(oldCompilation).Symbol); + Assert.Equal(expectedNewSymbol, symbolKey.Resolve(newCompilation).Symbol); break; case SemanticEditKind.Delete: @@ -352,25 +352,25 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) // Symbol key will happily resolve to a definition part that has no implementation, so we validate that // differently if (expectedOldSymbol.IsPartialDefinition() && - symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol is ISymbol resolvedSymbol) + symbolKey.Resolve(oldCompilation).Symbol is ISymbol resolvedSymbol) { Assert.Equal(expectedOldSymbol, resolvedSymbol.PartialDefinitionPart()); Assert.Equal(null, resolvedSymbol.PartialImplementationPart()); } else { - Assert.Equal(expectedOldSymbol, symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol); + Assert.Equal(expectedOldSymbol, symbolKey.Resolve(oldCompilation).Symbol); // When we're deleting a symbol, and have a deleted symbol container, it means the symbol wasn't really deleted, // but rather had its signature changed in some way. Some of those ways, like changing the return type, are not // represented in the symbol key, so the check below would fail, so we skip it. if (expectedSemanticEdit.DeletedSymbolContainerProvider is null) { - Assert.Equal(null, symbolKey.Resolve(newCompilation, ignoreAssemblyKey: true).Symbol); + Assert.Equal(null, symbolKey.Resolve(newCompilation).Symbol); } } - var deletedSymbolContainer = actualSemanticEdit.DeletedSymbolContainer?.Resolve(newCompilation, ignoreAssemblyKey: true).Symbol; + var deletedSymbolContainer = actualSemanticEdit.DeletedSymbolContainer?.Resolve(newCompilation).Symbol; AssertEx.AreEqual( deletedSymbolContainer, expectedSemanticEdit.DeletedSymbolContainerProvider?.Invoke(newCompilation), @@ -380,7 +380,7 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) case SemanticEditKind.Insert or SemanticEditKind.Replace: expectedNewSymbol = expectedSemanticEdit.SymbolProvider(newCompilation); - Assert.Equal(expectedNewSymbol, symbolKey.Resolve(newCompilation, ignoreAssemblyKey: true).Symbol); + Assert.Equal(expectedNewSymbol, symbolKey.Resolve(newCompilation).Symbol); break; default: @@ -390,7 +390,7 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) // Partial types must match: AssertEx.AreEqual( expectedSemanticEdit.PartialType?.Invoke(newCompilation), - actualSemanticEdit.PartialType?.Resolve(newCompilation, ignoreAssemblyKey: true).Symbol, + actualSemanticEdit.PartialType?.Resolve(newCompilation).Symbol, message: $"{message}, {editKind}({expectedNewSymbol ?? expectedOldSymbol}): Partial types do not match"); var expectedSyntaxMap = expectedSemanticEdit.GetSyntaxMap();