Ejemplo n.º 1
0
        private SourceItemHandler CreateInstance(UnconfiguredProject project = null, IWorkspaceProjectContext context = null)
        {
            project = project ?? UnconfiguredProjectFactory.Create();
            context = context ?? IWorkspaceProjectContextFactory.Create();

            return(new SourceItemHandler(project, context));
        }
Ejemplo n.º 2
0
        public void UniqueSourceFilesPushedToWorkspace()
        {
            var             sourceFilesPushedToWorkspace = new HashSet <string>(StringComparers.Paths);
            Action <string> onSourceFileAdded            = s => Assert.True(sourceFilesPushedToWorkspace.Add(s));
            Action <string> onSourceFileRemoved          = s => sourceFilesPushedToWorkspace.Remove(s);

            var project = UnconfiguredProjectFactory.Create(filePath: @"C:\Myproject.csproj");
            var context = IWorkspaceProjectContextFactory.CreateForSourceFiles(project, onSourceFileAdded, onSourceFileRemoved);
            var logger  = Mock.Of <IProjectLogger>();

            var handler    = new SourceItemHandler(project, context);
            var projectDir = Path.GetDirectoryName(project.FullPath);
            var added      = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new[] { @"C:\file1.cs", @"C:\file2.cs", @"C:\file1.cs" }, baseDirectory: projectDir, sdkDirectory: null));
            var empty      = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new string[] { }, baseDirectory: projectDir, sdkDirectory: null));

            handler.Handle(10, added: added, removed: empty, isActiveContext: true, logger: logger);

            Assert.Equal(2, sourceFilesPushedToWorkspace.Count);
            Assert.Contains(@"C:\file1.cs", sourceFilesPushedToWorkspace);
            Assert.Contains(@"C:\file2.cs", sourceFilesPushedToWorkspace);

            var removed = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new[] { @"C:\file1.cs", @"C:\file1.cs" }, baseDirectory: projectDir, sdkDirectory: null));

            handler.Handle(10, added: empty, removed: removed, isActiveContext: true, logger: logger);

            Assert.Equal(1, sourceFilesPushedToWorkspace.Count);
            Assert.Contains(@"C:\file2.cs", sourceFilesPushedToWorkspace);
        }
Ejemplo n.º 3
0
        public void DuplicateMetadataReferencesPushedToWorkspace()
        {
            var             referencesPushedToWorkspace = new HashSet <string>(StringComparers.Paths);
            Action <string> onReferenceAdded            = s => referencesPushedToWorkspace.Add(s);
            Action <string> onReferenceRemoved          = s => referencesPushedToWorkspace.Remove(s);

            var project = UnconfiguredProjectFactory.Create(filePath: @"C:\Myproject.csproj");
            var context = IWorkspaceProjectContextFactory.CreateForMetadataReferences(project, onReferenceAdded, onReferenceRemoved);

            var handler    = new MetadataReferenceItemHandler(project);
            var projectDir = Path.GetDirectoryName(project.FullPath);
            var added      = CSharpCommandLineParser.Default.Parse(args: new[] { @"/reference:C:\Assembly1.dll", @"/reference:C:\Assembly2.dll", @"/reference:C:\Assembly1.dll" }, baseDirectory: projectDir, sdkDirectory: null);
            var empty      = CSharpCommandLineParser.Default.Parse(args: new string[] { }, baseDirectory: projectDir, sdkDirectory: null);

            handler.Handle(added: added, removed: empty, context: context, isActiveContext: true);

            Assert.Equal(2, referencesPushedToWorkspace.Count);
            Assert.Contains(@"C:\Assembly1.dll", referencesPushedToWorkspace);
            Assert.Contains(@"C:\Assembly2.dll", referencesPushedToWorkspace);

            var removed = CSharpCommandLineParser.Default.Parse(args: new[] { @"/reference:C:\Assembly1.dll", @"/reference:C:\Assembly1.dll" }, baseDirectory: projectDir, sdkDirectory: null);

            handler.Handle(added: empty, removed: removed, context: context, isActiveContext: true);

            Assert.Equal(1, referencesPushedToWorkspace.Count);
            Assert.Contains(@"C:\Assembly2.dll", referencesPushedToWorkspace);
        }
        public void Handle_WhenMSBuildProjectFullPathPropertyChanged_SetsProjectFilePath()
        {
            var context = IWorkspaceProjectContextFactory.Create();

            context.ProjectFilePath = @"ProjectFilePath";

            var handler = CreateInstance(context: context);

            var projectChange = IProjectChangeDescriptionFactory.FromJson(
                @"{
    ""Difference"": { 
        ""AnyChanges"": true,
        ""ChangedProperties"": [ ""MSBuildProjectFullPath"" ]
    },
    ""After"": { 
        ""Properties"": {
            ""MSBuildProjectFullPath"": ""NewProjectFilePath""
        }
    }
}");

            Handle(handler, projectChange);

            Assert.Equal(@"NewProjectFilePath", context.ProjectFilePath);
        }
        public void DuplicateMetadataReferencesPushedToWorkspace()
        {
            var             referencesPushedToWorkspace = new HashSet <string>(StringComparers.Paths);
            Action <string> onReferenceAdded            = s => referencesPushedToWorkspace.Add(s);
            Action <string> onReferenceRemoved          = s => referencesPushedToWorkspace.Remove(s);

            var project = UnconfiguredProjectFactory.Create(filePath: @"C:\Myproject.csproj");
            var context = IWorkspaceProjectContextFactory.CreateForMetadataReferences(project, onReferenceAdded, onReferenceRemoved);
            var logger  = Mock.Of <IProjectLogger>();

            var handler    = new MetadataReferenceItemHandler(project, context);
            var projectDir = Path.GetDirectoryName(project.FullPath);
            var added      = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new[] { @"/reference:C:\Assembly1.dll", @"/reference:C:\Assembly2.dll", @"/reference:C:\Assembly1.dll" }, baseDirectory: projectDir, sdkDirectory: null));
            var empty      = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new string[] { }, baseDirectory: projectDir, sdkDirectory: null));

            handler.Handle(10, added: added, removed: empty, isActiveContext: true, logger: logger);

            AssertEx.CollectionLength(referencesPushedToWorkspace, 2);
            Assert.Contains(@"C:\Assembly1.dll", referencesPushedToWorkspace);
            Assert.Contains(@"C:\Assembly2.dll", referencesPushedToWorkspace);

            var removed = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new[] { @"/reference:C:\Assembly1.dll", @"/reference:C:\Assembly1.dll" }, baseDirectory: projectDir, sdkDirectory: null));

            handler.Handle(10, added: empty, removed: removed, isActiveContext: true, logger: logger);

            Assert.Single(referencesPushedToWorkspace);
            Assert.Contains(@"C:\Assembly2.dll", referencesPushedToWorkspace);
        }
        public void Constructor_NullAsProject_ThrowsArgumentNull()
        {
            var context = IWorkspaceProjectContextFactory.Create();

            Assert.Throws <ArgumentNullException>("project", () => {
                new MetadataReferenceItemHandler((UnconfiguredProject)null, context);
            });
        }
        public void Handle_NullAsProjectChange_ThrowsArgumentNull()
        {
            var handler = CreateInstance();
            var context = IWorkspaceProjectContextFactory.Create();

            Assert.Throws <ArgumentNullException>("projectChange", () => {
                handler.Handle((IProjectChangeDescription)null, context, true);
            });
        }
        public void Constructor_NullAsProject_ThrowsArgumentNull()
        {
            var context = IWorkspaceProjectContextFactory.Create();

            Assert.Throws <ArgumentNullException>("project", () =>
            {
                new AdditionalFilesItemHandler((UnconfiguredProject)null);
            });
        }
Ejemplo n.º 9
0
        public void Initialize_WhenAlreadyInitialized_ThrowsInvalidOperation()
        {
            var handler = CreateInstance();

            var workspaceContext = IWorkspaceProjectContextFactory.Create();

            handler.Initialize(workspaceContext);

            Assert.Throws <InvalidOperationException>(() =>
            {
                handler.Initialize(workspaceContext);
            });
        }
        public void RootedSourceFilesPushedToWorkspace()
        {
            var             sourceFilesPushedToWorkspace = new HashSet <string>(StringComparers.Paths);
            Action <string> onSourceFileAdded            = s => Assert.True(sourceFilesPushedToWorkspace.Add(s));
            Action <string> onSourceFileRemoved          = s => sourceFilesPushedToWorkspace.Remove(s);

            var project = UnconfiguredProjectFactory.Create(filePath: @"C:\ProjectFolder\Myproject.csproj");
            var context = IWorkspaceProjectContextFactory.CreateForSourceFiles(project, onSourceFileAdded, onSourceFileRemoved);

            var handler    = new SourceItemHandler(project, IPhysicalProjectTreeFactory.Create());
            var projectDir = Path.GetDirectoryName(project.FullPath);
            var added      = CSharpCommandLineParser.Default.Parse(args: new[] { @"file1.cs", @"..\ProjectFolder\file1.cs" }, baseDirectory: projectDir, sdkDirectory: null);
            var removed    = CSharpCommandLineParser.Default.Parse(args: new string[] { }, baseDirectory: projectDir, sdkDirectory: null);

            handler.Handle(added: added, removed: removed, context: context, isActiveContext: true);

            Assert.Equal(1, sourceFilesPushedToWorkspace.Count);
            Assert.Contains(@"C:\ProjectFolder\file1.cs", sourceFilesPushedToWorkspace);
        }
        public void RootedReferencesPushedToWorkspace()
        {
            var             referencesPushedToWorkspace = new HashSet <string>(StringComparers.Paths);
            Action <string> onReferenceAdded            = s => referencesPushedToWorkspace.Add(s);
            Action <string> onReferenceRemoved          = s => referencesPushedToWorkspace.Remove(s);

            var project = UnconfiguredProjectFactory.Create(filePath: @"C:\ProjectFolder\Myproject.csproj");
            var context = IWorkspaceProjectContextFactory.CreateForMetadataReferences(project, onReferenceAdded, onReferenceRemoved);

            var handler    = new MetadataReferenceItemHandler(project, context);
            var projectDir = Path.GetDirectoryName(project.FullPath);
            var added      = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new[] { @"/reference:Assembly1.dll", @"/reference:C:\ProjectFolder\Assembly2.dll", @"/reference:..\ProjectFolder\Assembly3.dll" }, baseDirectory: projectDir, sdkDirectory: null));
            var removed    = BuildOptions.FromCommandLineArguments(CSharpCommandLineParser.Default.Parse(args: new string[] { }, baseDirectory: projectDir, sdkDirectory: null));

            handler.Handle(10, added: added, removed: removed, isActiveContext: true);

            Assert.Equal(3, referencesPushedToWorkspace.Count);
            Assert.Contains(@"C:\ProjectFolder\Assembly1.dll", referencesPushedToWorkspace);
            Assert.Contains(@"C:\ProjectFolder\Assembly2.dll", referencesPushedToWorkspace);
            Assert.Contains(@"C:\ProjectFolder\Assembly3.dll", referencesPushedToWorkspace);
        }
        public void Handle_WhenMSBuildProjectFullPathPropertyNotChanged_DoesNothing()
        {
            var context = IWorkspaceProjectContextFactory.Create();

            context.ProjectFilePath = @"ProjectFilePath";
            context.DisplayName     = "DisplayName";

            var handler = CreateInstance(context: context);

            var projectChange = IProjectChangeDescriptionFactory.FromJson(
                @"{
    ""Difference"": { 
        ""AnyChanges"": true
    }
}");

            Handle(handler, projectChange);

            Assert.Equal(@"ProjectFilePath", context.ProjectFilePath);
            Assert.Equal(@"DisplayName", context.DisplayName);
        }
        public void Handle_WhenMSBuildProjectFullPathPropertyChanged_SetsDisplayNameToFileNameWithoutExtension()
        {
            var context = IWorkspaceProjectContextFactory.Create();

            var handler = CreateInstance(context: context);

            var projectChange = IProjectChangeDescriptionFactory.FromJson(
                @"{
    ""Difference"": { 
        ""AnyChanges"": true,
        ""ChangedProperties"": [ ""MSBuildProjectFullPath"" ]
    },
    ""After"": { 
        ""Properties"": {
            ""MSBuildProjectFullPath"": ""C:\\Project\\Project.csproj""
        }
    }
}");

            Handle(handler, projectChange);

            Assert.Equal(@"Project", context.DisplayName);
        }
        public void Handle_WhenMSBuildProjectFullPathPropertyChangedAndMultitargeting_IncludeDimensionValuesInDisplayName(string dimensionNames, string dimensionValues, string implicitDimensionNames, string expected)
        {
            var context = IWorkspaceProjectContextFactory.Create();
            var implicitlyActiveDimensionProvider = IImplicitlyActiveDimensionProviderFactory.ImplementGetImplicitlyActiveDimensions(n => implicitDimensionNames.SplitReturningEmptyIfEmpty('|'));
            var configuration = ProjectConfigurationFactory.Create(dimensionNames, dimensionValues);
            var handler       = CreateInstance(configuration, implicitlyActiveDimensionProvider, context);

            var projectChange = IProjectChangeDescriptionFactory.FromJson(
                @"{
    ""Difference"": { 
        ""AnyChanges"": true,
        ""ChangedProperties"": [ ""MSBuildProjectFullPath"" ]
    },
    ""After"": { 
        ""Properties"": {
            ""MSBuildProjectFullPath"": ""C:\\Project\\Project.csproj""
        }
    }
}");

            Handle(handler, projectChange);

            Assert.Equal(expected, context.DisplayName);
        }
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            string projectFilename,
            IReadOnlyDictionary<string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary<string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);
            if (languageName == null)
            {
                return null;
            }

            DeferredProjectInformation projectInfo;
            if (!allProjectInfos.TryGetValue(projectFilename, out projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return null;
            }

            var commandLineParser = _workspaceServices.GetLanguageServices(languageName).GetService<ICommandLineParserService>();
            var projectDirectory = PathUtilities.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = PathUtilities.GetFileName(projectFilename, includeExtension: false);

            // `AbstractProject` only sets the filename if it actually exists.  Since we want 
            // our ids to match, mimic that behavior here.
            var projectId = File.Exists(projectFilename)
                ? GetOrCreateProjectIdForPath(projectFilename, projectName)
                : GetOrCreateProjectIdForPath(projectName, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            AbstractProject project;
            if (_projectMap.TryGetValue(projectId, out project))
            {
                return project;
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5 = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;

            // If the index is stale, it might give us a path that doesn't exist anymore that the 
            // solution doesn't know about - be resilient to that case.
            Guid projectGuid;
            try
            {
                projectGuid = solution5.GetGuidOfProjectFile(projectFilename);
            }
            catch (ArgumentException)
            {
                var message = $"Failed to get the project guid for '{projectFilename}' from the solution, using  random guid instead.";
                Debug.Fail(message);
                OutputToOutputWindow(message);
                projectGuid = Guid.NewGuid();
            }

            // NOTE: If the indexing service fails for a project, it will give us an *empty*
            // target path, which we aren't prepared to handle.  Instead, convert it to a *null*
            // value, which we do handle.
            var outputPath = projectInfo.TargetPath;
            if (outputPath == string.Empty)
            {
                outputPath = null;
            }

            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: outputPath);

            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet<string>();
            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));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.MetadataReferences)
            {
                string possibleProjectReference;
                if (targetPathsToProjectPaths.TryGetValue(reference.Reference, out possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(reference.Reference, reference.Properties);
            }

            foreach (var reference in commandLineArguments.AnalyzerReferences)
            {
                var path = reference.FilePath;
                if (!PathUtilities.IsAbsolute(path))
                {
                    path = PathUtilities.CombineAbsoluteAndRelativePaths(
                        projectDirectory,
                        path);
                }

                projectContext.AddAnalyzerReference(path);
            }

            return (AbstractProject)projectContext;
        }
Ejemplo n.º 16
0
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            IAnalyzerAssemblyLoader analyzerAssemblyLoader,
            string projectFilename,
            IReadOnlyDictionary <string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary <string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);

            if (languageName == null)
            {
                return(null);
            }

            if (!allProjectInfos.TryGetValue(projectFilename, out var projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return(null);
            }

            var commandLineParser    = _workspaceServices.GetLanguageServices(languageName).GetService <ICommandLineParserService>();
            var projectDirectory     = PathUtilities.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = PathUtilities.GetFileName(projectFilename, includeExtension: false);

            // `AbstractProject` only sets the filename if it actually exists.  Since we want
            // our ids to match, mimic that behavior here.
            var projectId = File.Exists(projectFilename)
                ? GetOrCreateProjectIdForPath(projectFilename, projectName)
                : GetOrCreateProjectIdForPath(projectName, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            if (_projectMap.TryGetValue(projectId, out var project))
            {
                return(project);
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5 = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;

            // If the index is stale, it might give us a path that doesn't exist anymore that the
            // solution doesn't know about - be resilient to that case.
            Guid projectGuid;

            try
            {
                projectGuid = solution5.GetGuidOfProjectFile(projectFilename);
            }
            catch (ArgumentException)
            {
                var message = $"Failed to get the project guid for '{projectFilename}' from the solution, using  random guid instead.";
                Debug.Fail(message);
                OutputToOutputWindow(message);
                projectGuid = Guid.NewGuid();
            }

            // NOTE: If the indexing service fails for a project, it will give us an *empty*
            // target path, which we aren't prepared to handle.  Instead, convert it to a *null*
            // value, which we do handle.
            var outputPath = projectInfo.TargetPath;

            if (outputPath == string.Empty)
            {
                outputPath = null;
            }

            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: outputPath);

            project = (AbstractProject)projectContext;
            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet <string>();

            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));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        analyzerAssemblyLoader,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver))
            {
                // 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;
                if (targetPathsToProjectPaths.TryGetValue(path, out var possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(path, reference.Properties);
            }

            foreach (var reference in commandLineArguments.ResolveAnalyzerReferences(analyzerAssemblyLoader))
            {
                var path = reference.FullPath;
                if (!PathUtilities.IsAbsolute(path))
                {
                    path = PathUtilities.CombineAbsoluteAndRelativePaths(
                        projectDirectory,
                        path);
                }

                projectContext.AddAnalyzerReference(path);
            }

            return((AbstractProject)projectContext);
        }
Ejemplo n.º 17
0
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            IAnalyzerAssemblyLoader analyzerAssemblyLoader,
            string projectFilename,
            IReadOnlyDictionary <string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary <string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);

            if (languageName == null)
            {
                return(null);
            }

            if (!allProjectInfos.TryGetValue(projectFilename, out var projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return(null);
            }

            // TODO: Should come from .sln file?
            var projectName = PathUtilities.GetFileName(projectFilename, includeExtension: false);

            // `AbstractProject` only sets the filename if it actually exists.  Since we want
            // our ids to match, mimic that behavior here.
            var projectId = File.Exists(projectFilename)
                ? GetOrCreateProjectIdForPath(projectFilename, projectName)
                : GetOrCreateProjectIdForPath(projectName, projectName);

            // See if something has already created this project - it's not deferred, the AnyCode design time build
            // failed so we force loaded it, or we already created a deferred project and we're in a recursive call
            // to find a ProjectReference
            if (_projectMap.TryGetValue(projectId, out var project))
            {
                return(project);
            }

            // If the project system has opted this project out of deferred loading, or AnyCode
            // was unable to get command line info for it, we can't create a project for it.
            // NOTE: We need to check this even though it happened in CreateDeferredProjects
            // because we could be in a recursive call from a project reference below.
            var solution7 = (IVsSolution7)_vsSolution;

            if (DesignTimeBuildFailed(projectInfo) ||
                !solution7.IsDeferredProjectLoadAllowed(projectFilename))
            {
                return(null);
            }

            var commandLineParser    = _workspaceServices.GetLanguageServices(languageName).GetService <ICommandLineParserService>();
            var projectDirectory     = PathUtilities.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");

            var projectGuid    = GetProjectGuid(projectFilename);
            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: projectInfo.TargetPath);

            project = (AbstractProject)projectContext;
            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            var addedSourceFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                if (addedSourceFilePaths.Add(sourceFile.Path))
                {
                    projectContext.AddSourceFile(sourceFile.Path);
                }
            }

            var addedAdditionalFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var additionalFile in commandLineArguments.AdditionalFiles)
            {
                if (addedAdditionalFilePaths.Add(additionalFile.Path))
                {
                    projectContext.AddAdditionalFile(additionalFile.Path);
                }
            }

            var metadataReferences     = commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver).AsImmutable();
            var addedProjectReferences = new HashSet <string>();

            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                var referencedProject = TryFindExistingProjectForProjectReference(projectReferencePath, metadataReferences);
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        analyzerAssemblyLoader,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"\t\tFailed to create a project for '{projectReferencePath}'.");
                }
            }

            var addedReferencePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var reference in metadataReferences)
            {
                var path = GetReferencePath(reference);
                if (targetPathsToProjectPaths.TryGetValue(path, out var possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                if (addedReferencePaths.Add(path))
                {
                    projectContext.AddMetadataReference(path, reference.Properties);
                }
            }

            var addedAnalyzerPaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var reference in commandLineArguments.ResolveAnalyzerReferences(analyzerAssemblyLoader))
            {
                var path = reference.FullPath;
                if (!PathUtilities.IsAbsolute(path))
                {
                    path = PathUtilities.CombineAbsoluteAndRelativePaths(
                        projectDirectory,
                        path);
                }

                if (addedAnalyzerPaths.Add(path))
                {
                    projectContext.AddAnalyzerReference(path);
                }
            }

            return((AbstractProject)projectContext);
        }
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            string projectFilename,
            IReadOnlyDictionary<string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary<string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);
            if (languageName == null)
            {
                return null;
            }

            DeferredProjectInformation projectInfo;
            if (!allProjectInfos.TryGetValue(projectFilename, out projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return null;
            }

            var commandLineParser = _workspaceServices.GetLanguageServices(languageName).GetService<ICommandLineParserService>();
            var projectDirectory = Path.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = Path.GetFileNameWithoutExtension(projectFilename);
            var projectId = GetOrCreateProjectIdForPath(projectFilename, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            AbstractProject project;
            if (_projectMap.TryGetValue(projectId, out project))
            {
                return project;
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5 = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;
            var projectGuid = solution5.GetGuidOfProjectFile(projectFilename);
            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: projectInfo.TargetPath);

            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet<string>();
            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                var referencedProject = ImmutableProjects.SingleOrDefault(p => StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.MetadataReferences)
            {
                string possibleProjectReference;
                if (targetPathsToProjectPaths.TryGetValue(reference.Reference, out possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(reference.Reference, reference.Properties);
            }

            foreach (var reference in commandLineArguments.AnalyzerReferences)
            {
                projectContext.AddAnalyzerReference(reference.FilePath);
            }

            return (AbstractProject)projectContext;
        }
Ejemplo n.º 19
0
 public FSharpWorkspaceProjectContextFactory(IWorkspaceProjectContextFactory factory, IThreadingContext threadingContext)
 {
     _factory          = factory;
     _threadingContext = threadingContext;
 }
Ejemplo n.º 20
0
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            string projectFilename,
            IReadOnlyDictionary <string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary <string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);

            if (languageName == null)
            {
                return(null);
            }

            DeferredProjectInformation projectInfo;

            if (!allProjectInfos.TryGetValue(projectFilename, out projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return(null);
            }

            var commandLineParser    = _workspaceServices.GetLanguageServices(languageName).GetService <ICommandLineParserService>();
            var projectDirectory     = Path.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = Path.GetFileNameWithoutExtension(projectFilename);
            var projectId   = GetOrCreateProjectIdForPath(projectFilename, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            AbstractProject project;

            if (_projectMap.TryGetValue(projectId, out project))
            {
                return(project);
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5      = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;
            var projectGuid    = solution5.GetGuidOfProjectFile(projectFilename);
            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: projectInfo.TargetPath);

            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet <string>();

            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                var referencedProject = ImmutableProjects.SingleOrDefault(p => StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.MetadataReferences)
            {
                string possibleProjectReference;
                if (targetPathsToProjectPaths.TryGetValue(reference.Reference, out possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(reference.Reference, reference.Properties);
            }

            foreach (var reference in commandLineArguments.AnalyzerReferences)
            {
                projectContext.AddAnalyzerReference(reference.FilePath);
            }

            return((AbstractProject)projectContext);
        }