diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs index 426b47d6aac8bc26db3f12dd64363cc09a8363f5..b10e98c162895cdfcbc3f58f6ffeb7c95a688b7e 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectTracker.cs @@ -761,14 +761,11 @@ private void OutputToOutputWindow(string message) projectContext.AddAdditionalFile(sourceFile.Path); } + var metadataReferences = commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver).AsImmutable(); var addedProjectReferences = new HashSet(); foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths) { - // NOTE: ImmutableProjects might contain projects for other languages like - // Xaml, or Typescript where the project file ends up being identical. - var referencedProject = ImmutableProjects.SingleOrDefault( - p => (p.Language == LanguageNames.CSharp || p.Language == LanguageNames.VisualBasic) - && StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath)); + var referencedProject = TryFindExistingProjectForProjectReference(projectReferencePath, metadataReferences); if (referencedProject == null) { referencedProject = GetOrCreateProjectFromArgumentsAndReferences( @@ -809,15 +806,9 @@ private void OutputToOutputWindow(string message) } } - foreach (var reference in commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver)) + foreach (var reference in metadataReferences) { - // Some references may fail to be resolved - if they are, we'll still pass them - // through, in case they come into existence later (they may be built by other - // parts of the build system). - var unresolvedReference = reference as UnresolvedMetadataReference; - var path = unresolvedReference == null - ? ((PortableExecutableReference)reference).FilePath - : unresolvedReference.Reference; + var path = GetReferencePath(reference); if (targetPathsToProjectPaths.TryGetValue(path, out var possibleProjectReference) && addedProjectReferences.Contains(possibleProjectReference)) { @@ -844,6 +835,47 @@ private void OutputToOutputWindow(string message) return (AbstractProject)projectContext; } + private AbstractProject TryFindExistingProjectForProjectReference(string projectReferencePath, ImmutableArray metadataReferences) + { + // NOTE: ImmutableProjects might contain projects for other languages like + // Xaml, or Typescript where the project file ends up being identical. + AbstractProject candidate = null; + foreach (var existingProject in ImmutableProjects) + { + if (existingProject.Language != LanguageNames.CSharp && existingProject.Language != LanguageNames.VisualBasic) + { + continue; + } + + if (!StringComparer.OrdinalIgnoreCase.Equals(existingProject.ProjectFilePath, projectReferencePath)) + { + continue; + } + + // There might be multiple projects that have the same project file path and language in the case of + // cross-targeted .NET Core project. To support that, we'll try to find the one with the output path + // that matches one of the metadata references we're trying to add. If we don't find any, then we'll + // settle one with a matching project file path. + candidate = candidate ?? existingProject; + if (metadataReferences.Contains(mr => StringComparer.OrdinalIgnoreCase.Equals(GetReferencePath(mr), existingProject.BinOutputPath))) + { + return existingProject; + } + } + + return candidate; + } + + private static string GetReferencePath(MetadataReference mr) + { + // Some references may fail to be resolved - if they are, we'll still pass them + // through, in case they come into existence later (they may be built by other + // parts of the build system). + return mr is UnresolvedMetadataReference umr + ? umr.Reference + : ((PortableExecutableReference)mr).FilePath; + } + private static string GetLanguageOfProject(string projectFilename) { switch (PathUtilities.GetExtension(projectFilename)) diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs index 06f5d8fa866288d5ddd28ce0a6b42393b4570c28..c426af31f8e25be8e7c715dc6131c8b058660cd4 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs @@ -152,7 +152,7 @@ public EnvDTE.TextPoint StartPoint { get { - var point = FileCodeModel.EnsureEditor(() => CodeModelService.GetStartPoint(LookupNode())); + var point = CodeModelService.GetStartPoint(LookupNode()); if (point == null) { return null; @@ -178,7 +178,7 @@ public EnvDTE.TextPoint EndPoint public virtual EnvDTE.TextPoint GetStartPoint(EnvDTE.vsCMPart part) { - var point = FileCodeModel.EnsureEditor(() => CodeModelService.GetStartPoint(LookupNode(), part)); + var point = CodeModelService.GetStartPoint(LookupNode(), part); if (point == null) { return null;