public AnalyzerConfigOptionsResult?GetAnalyzerConfigOptions() { // We need to find the analyzer config options at the root of the project. // Currently, there is no compiler API to query analyzer config options for a directory in a language agnostic fashion. // So, we use a dummy language-specific file name appended to the project directory to query analyzer config options. var projectDirectory = PathUtilities.GetDirectoryName(_projectInfo.FilePath); if (!PathUtilities.IsAbsolute(projectDirectory)) { return(null); } var fileName = Guid.NewGuid().ToString(); string sourceFilePath; switch (_projectInfo.Language) { case LanguageNames.CSharp: // Suppression should be removed or addressed https://github.com/dotnet/roslyn/issues/41636 sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.cs") !; break; case LanguageNames.VisualBasic: // Suppression should be removed or addressed https://github.com/dotnet/roslyn/issues/41636 sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.vb") !; break; default: return(null); } return(_lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(sourceFilePath)); }
/// <summary> /// Read the references from the project.lock.json file. /// </summary> internal static ImmutableArray <string> ReadProjectLockJson(string packagesDirectory, TextReader reader) { JObject obj; using (var jsonReader = new JsonTextReader(reader)) { obj = JObject.Load(jsonReader); } var builder = ArrayBuilder <string> .GetInstance(); var targets = (JObject)GetPropertyValue(obj, "targets"); foreach (var target in targets) { if (target.Key == ProjectLockJsonFramework) { foreach (var package in (JObject)target.Value) { var packageRoot = PathUtilities.CombineAbsoluteAndRelativePaths(packagesDirectory, package.Key); var runtime = (JObject)GetPropertyValue((JObject)package.Value, "runtime"); if (runtime == null) { continue; } foreach (var item in runtime) { var path = PathUtilities.CombinePossiblyRelativeAndRelativePaths(packageRoot, item.Key); builder.Add(path); } } break; } } return(builder.ToImmutableAndFree()); }
/// <exception cref="IOException"/> /// <exception cref="BadImageFormatException" /> private AssemblyMetadata CreateAssemblyMetadata( FileKey fileKey, ModuleMetadata manifestModule, List <ITemporaryStreamStorage> storages, Func <FileKey, List <ITemporaryStreamStorage>, ModuleMetadata> moduleMetadataFactory) { ImmutableArray <ModuleMetadata> .Builder moduleBuilder = null; string assemblyDir = null; foreach (string moduleName in manifestModule.GetModuleNames()) { if (moduleBuilder == null) { moduleBuilder = ImmutableArray.CreateBuilder <ModuleMetadata>(); moduleBuilder.Add(manifestModule); assemblyDir = Path.GetDirectoryName(fileKey.FullPath); } var moduleFileKey = FileKey.Create(PathUtilities.CombineAbsoluteAndRelativePaths(assemblyDir, moduleName)); var metadata = moduleMetadataFactory(moduleFileKey, storages); moduleBuilder.Add(metadata); } var modules = (moduleBuilder != null) ? moduleBuilder.ToImmutable() : ImmutableArray.Create(manifestModule); return(AssemblyMetadata.Create(modules)); }
public ImmutableDictionary <string, ReportDiagnostic> GetAnalyzerConfigSpecialDiagnosticOptions() { // We need to find the analyzer config options at the root of the project. // Currently, there is no compiler API to query analyzer config options for a directory in a language agnostic fashion. // So, we use a dummy language-specific file name appended to the project directory to query analyzer config options. var projectDirectory = PathUtilities.GetDirectoryName(_projectInfo.FilePath); if (!PathUtilities.IsAbsolute(projectDirectory)) { return(ImmutableDictionary <string, ReportDiagnostic> .Empty); } var fileName = Guid.NewGuid().ToString(); string sourceFilePath; switch (_projectInfo.Language) { case LanguageNames.CSharp: sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.cs"); break; case LanguageNames.VisualBasic: sourceFilePath = PathUtilities.CombineAbsoluteAndRelativePaths(projectDirectory, $"{fileName}.vb"); break; default: return(ImmutableDictionary <string, ReportDiagnostic> .Empty); } return(_lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(sourceFilePath).TreeOptions); }
internal static string?ResolveStrongNameKeyFile(string path, StrongNameFileSystem fileSystem, ImmutableArray <string> keyFileSearchPaths) { // Dev11: key path is simply appended to the search paths, even if it starts with the current (parent) directory ("." or ".."). // This is different from PathUtilities.ResolveRelativePath. if (PathUtilities.IsAbsolute(path)) { if (fileSystem.FileExists(path)) { return(FileUtilities.TryNormalizeAbsolutePath(path)); } return(path); } foreach (var searchPath in keyFileSearchPaths) { string?combinedPath = PathUtilities.CombineAbsoluteAndRelativePaths(searchPath, path); Debug.Assert(combinedPath == null || PathUtilities.IsAbsolute(combinedPath)); if (fileSystem.FileExists(combinedPath)) { return(FileUtilities.TryNormalizeAbsolutePath(combinedPath !)); } } return(null); }
/// <summary> /// Determines if the actual file path matches its logical path in project /// which is constructed as [project_root_path]\Logical\Folders\. The refactoring /// is triggered only when the two match. The reason of doing this is we don't really know /// the user's intention of keeping the file path out-of-sync with its logical path. /// </summary> private static bool IsDocumentPathRootedInProjectFolder(Document document) { var projectRoot = PathUtilities.GetDirectoryName(document.Project.FilePath); var folderPath = Path.Combine(document.Folders.ToArray()); var absoluteDircetoryPath = PathUtilities.GetDirectoryName(document.FilePath); var logicalDirectoryPath = PathUtilities.CombineAbsoluteAndRelativePaths(projectRoot, folderPath); return(PathUtilities.PathsEqual(absoluteDircetoryPath, logicalDirectoryPath)); }
protected (string folder, string filePath) CreateDocumentFilePath(string[] folder, string fileName = "DocumentA.cs") { if (folder == null || folder.Length == 0) { return(string.Empty, PathUtilities.CombineAbsoluteAndRelativePaths(ProjectRootPath, fileName)); } else { var folderPath = CreateFolderPath(folder); var relativePath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(folderPath, fileName); return(folderPath, PathUtilities.CombineAbsoluteAndRelativePaths(ProjectRootPath, relativePath)); } }
private static MetadataFileReferenceResolver CreateFileResolver(ImmutableArray <string> referencePaths, string baseDirectory) { var userProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var packagesDirectory = (userProfilePath == null) ? null : PathUtilities.CombineAbsoluteAndRelativePaths(userProfilePath, PathUtilities.CombinePossiblyRelativeAndRelativePaths(".nuget", "packages")); return(new DesktopMetadataReferenceResolver( new RelativePathReferenceResolver(referencePaths, baseDirectory), string.IsNullOrEmpty(packagesDirectory) ? null : new NuGetPackageResolverImpl(packagesDirectory), new GacFileResolver( architectures: GacFileResolver.Default.Architectures, // TODO (tomat) preferredCulture: System.Globalization.CultureInfo.CurrentCulture))); // TODO (tomat) }
internal override ImmutableArray <string> ResolveNuGetPackage(string reference) { string packageName; string packageVersion; if (!ParsePackageReference(reference, out packageName, out packageVersion)) { return(default(ImmutableArray <string>)); } try { var tempPath = PathUtilities.CombineAbsoluteAndRelativePaths(Path.GetTempPath(), Guid.NewGuid().ToString("D")); var tempDir = Directory.CreateDirectory(tempPath); try { // Create project.json. var projectJson = PathUtilities.CombineAbsoluteAndRelativePaths(tempPath, "project.json"); using (var stream = File.OpenWrite(projectJson)) using (var writer = new StreamWriter(stream)) { WriteProjectJson(writer, packageName, packageVersion); } // Run "nuget.exe restore project.json" to generate project.lock.json. NuGetRestore(projectJson); // Read the references from project.lock.json. var projectLockJson = PathUtilities.CombineAbsoluteAndRelativePaths(tempPath, "project.lock.json"); using (var stream = File.OpenRead(projectLockJson)) using (var reader = new StreamReader(stream)) { return(ReadProjectLockJson(_packagesDirectory, reader)); } } finally { tempDir.Delete(recursive: true); } } catch (IOException) { } catch (UnauthorizedAccessException) { } return(default(ImmutableArray <string>)); }
public void TestOpenCloseAnnalyzerConfigDocument() { var pid = ProjectId.CreateNewId(); var text = SourceText.From("public class C { }"); var version = VersionStamp.Create(); var analyzerConfigDocFilePath = PathUtilities.CombineAbsoluteAndRelativePaths( Temp.CreateDirectory().Path, ".editorconfig" ); var docInfo = DocumentInfo.Create( DocumentId.CreateNewId(pid), name: ".editorconfig", loader: TextLoader.From( TextAndVersion.Create(text, version, analyzerConfigDocFilePath) ), filePath: analyzerConfigDocFilePath ); var projInfo = ProjectInfo .Create( pid, version: VersionStamp.Default, name: "TestProject", assemblyName: "TestProject.dll", language: LanguageNames.CSharp ) .WithAnalyzerConfigDocuments(new[] { docInfo }); using (var ws = new AdhocWorkspace()) { ws.AddProject(projInfo); var doc = ws.CurrentSolution.GetAnalyzerConfigDocument(docInfo.Id); Assert.False(doc.TryGetText(out var currentText)); ws.OpenAnalyzerConfigDocument(docInfo.Id); doc = ws.CurrentSolution.GetAnalyzerConfigDocument(docInfo.Id); Assert.True(doc.TryGetText(out currentText)); Assert.True(doc.TryGetTextVersion(out var currentVersion)); Assert.Same(text, currentText); Assert.Equal(version, currentVersion); ws.CloseAnalyzerConfigDocument(docInfo.Id); doc = ws.CurrentSolution.GetAnalyzerConfigDocument(docInfo.Id); Assert.False(doc.TryGetText(out currentText)); } }
private static string?TryGetAnalyzerConfigPathForProjectOrDiagnosticConfiguration(Project project, Diagnostic?diagnostic) { if (project.AnalyzerConfigDocuments.Any()) { var diagnosticFilePath = PathUtilities.GetDirectoryName(diagnostic?.Location.SourceTree?.FilePath ?? project.FilePath); if (!PathUtilities.IsAbsolute(diagnosticFilePath)) { return(null); } // Currently, we use a simple heuristic to find existing .editorconfig file. // We start from the directory of the source file where the diagnostic was reported and walk up // the directory tree to find an .editorconfig file. // In future, we might change this algorithm, or allow end users to customize it based on options. var bestPath = string.Empty; AnalyzerConfigDocument?bestAnalyzerConfigDocument = null; foreach (var analyzerConfigDocument in project.AnalyzerConfigDocuments) { var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigDocument.FilePath); if (diagnosticFilePath.StartsWith(analyzerConfigDirectory) && analyzerConfigDirectory.Length > bestPath.Length) { bestPath = analyzerConfigDirectory; bestAnalyzerConfigDocument = analyzerConfigDocument; } } if (bestAnalyzerConfigDocument != null) { return(bestAnalyzerConfigDocument.FilePath); } } // Did not find any existing .editorconfig, so create one at root of the solution, if one exists. // If project is not part of a solution, then use project path. var solutionOrProjectFilePath = project.Solution?.FilePath ?? project.FilePath; if (!PathUtilities.IsAbsolute(solutionOrProjectFilePath)) { return(null); } var solutionOrProjectDirectoryPath = PathUtilities.GetDirectoryName(solutionOrProjectFilePath); return(PathUtilities.CombineAbsoluteAndRelativePaths(solutionOrProjectDirectoryPath, ".editorconfig")); }
public void CombinePaths() { Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"")); Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", null)); Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", null)); Assert.Null(PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"C:\goo")); Assert.Null(PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"C:goo")); Assert.Null(PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"\goo")); Assert.Equal(@"C:\x\y\goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x\y", @"goo")); Assert.Equal(@"C:\x/y\goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"goo")); Assert.Equal(@"C:\x/y\.\goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @".\goo")); Assert.Equal(@"C:\x/y\./goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"./goo")); Assert.Equal(@"C:\x/y\..\goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"..\goo")); Assert.Equal(@"C:\x/y\../goo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"../goo")); }
public void CombinePaths() { Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"")); Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", null)); Assert.Equal(@"C:\x/y", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", null)); Assert.Equal(null, PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"C:\foo")); Assert.Equal(null, PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"C:foo")); Assert.Equal(null, PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\", @"\foo")); Assert.Equal(@"C:\x\y\foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x\y", @"foo")); Assert.Equal(@"C:\x/y\foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"foo")); Assert.Equal(@"C:\x/y\.\foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @".\foo")); Assert.Equal(@"C:\x/y\./foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"./foo")); Assert.Equal(@"C:\x/y\..\foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"..\foo")); Assert.Equal(@"C:\x/y\../foo", PathUtilities.CombineAbsoluteAndRelativePaths(@"C:\x/y", @"../foo")); }
private ImmutableArray <ModuleMetadata> GetAllModules(ModuleMetadata manifestModule, string assemblyDir) { List <ModuleMetadata> moduleBuilder = null; foreach (string moduleName in manifestModule.GetModuleNames()) { if (moduleBuilder == null) { moduleBuilder = new List <ModuleMetadata>(); moduleBuilder.Add(manifestModule); } var module = CreateModuleMetadata(PathUtilities.CombineAbsoluteAndRelativePaths(assemblyDir, moduleName), prefetchEntireImage: false); moduleBuilder.Add(module); } return((moduleBuilder != null) ? moduleBuilder.ToImmutableArray() : ImmutableArray.Create(manifestModule)); }
private void NuGetRestore(string projectJsonPath) { // Load nuget.exe from same directory as current assembly. var nugetExePath = PathUtilities.CombineAbsoluteAndRelativePaths( PathUtilities.GetDirectoryName( CorLightup.Desktop.GetAssemblyLocation(typeof(NuGetPackageResolverImpl).GetTypeInfo().Assembly)), "nuget.exe"); var startInfo = new ProcessStartInfo() { FileName = nugetExePath, Arguments = $"restore \"{projectJsonPath}\" -PackagesDirectory \"{_packagesDirectory}\"", CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; _restore(startInfo); }
private void NormalizeAndSetBinOutputPathAndRelatedData(string binOutputPath) { if (binOutputPath != null) { // Ensure that binOutputPath is either null or a rooted path. // CPS might provide such invalid paths during initialization or when project is in unrestored state. if (binOutputPath == String.Empty) { binOutputPath = null; } else if (!PathUtilities.IsAbsolute(binOutputPath)) { // Make it a rooted path. var basePath = this.ContainingDirectoryPathOpt ?? Path.GetTempPath(); binOutputPath = PathUtilities.CombineAbsoluteAndRelativePaths(basePath, binOutputPath); } } // We need to ensure that the bin output path for the project has been initialized before we hookup the project with the project tracker. SetBinOutputPathAndRelatedData(binOutputPath); }
public async Task NoAction_FileNotRooted() { var filePath = PathUtilities.CombineAbsoluteAndRelativePaths(PathUtilities.GetPathRoot(ProjectFilePath), "Foo.cs"); var code = $@" <Workspace> <Project Language=""C#"" AssemblyName=""Assembly1"" FilePath=""{ProjectFilePath}"" CommonReferences=""true""> <Document FilePath=""{filePath}""> namespace [||]NS {{ class Class1 {{ }} }} </Document> </Project> </Workspace>"; await TestMissingInRegularAndScriptAsync(code); }
/// <summary> /// Resolves assembly strong name key file path. /// Internal for testing. /// </summary> /// <returns>Normalized key file path or null if not found.</returns> internal string ResolveStrongNameKeyFile(string path) { // Dev11: key path is simply appended to the search paths, even if it starts with the current (parent) directory ("." or ".."). // This is different from PathUtilities.ResolveRelativePath. if (PathUtilities.IsAbsolute(path)) { if (FileExists(path)) { if (touchedFiles != null) { touchedFiles.AddRead(path); } return(FileUtilities.NormalizeAbsolutePath(path)); } return(path); } foreach (var searchPath in this.keyFileSearchPaths) { string combinedPath = PathUtilities.CombineAbsoluteAndRelativePaths(searchPath, path); Debug.Assert(combinedPath == null || PathUtilities.IsAbsolute(combinedPath)); if (FileExists(combinedPath)) { if (touchedFiles != null) { touchedFiles.AddRead(combinedPath); } return(FileUtilities.NormalizeAbsolutePath(combinedPath)); } } return(null); }
/// <summary> /// This refactoring only supports non-linked document and linked document in the form of /// documents in multi-targeting project. Also for simplicity, we also don't support document /// what has different file path and logical path in project (i.e. [ProjectRoot] + `Document.Folders`). /// If the requirements above is met, we will return IDs of all documents linked to the specified /// document (inclusive), an array of single element will be returned for non-linked document. /// </summary> private static bool IsSupportedLinkedDocument(Document document, out ImmutableArray <DocumentId> allDocumentIds) { var solution = document.Project.Solution; var linkedDocumentids = document.GetLinkedDocumentIds(); // TODO: figure out how to properly determine if and how a document is linked using project system. // If we found a linked document which is part of a project with differenct project file, // then it's an actual linked file (i.e. not a multi-targeting project). We don't support that, because // we don't know which default namespace and folder path we should use to construct target // namespace. if (linkedDocumentids.Any(id => !PathUtilities.PathsEqual(solution.GetDocument(id).Project.FilePath, document.Project.FilePath))) { allDocumentIds = default; return(false); } // Now determine if the actual file path matches its logical path in project // which is constructed as <project root path>\Logical\Folders\. The refactoring // is triggered only when the two match. The reason of doing this is we don't really know // the user's intention of keeping the file path out-of-sync with its logical path. var projectRoot = PathUtilities.GetDirectoryName(document.Project.FilePath); var folderPath = Path.Combine(document.Folders.ToArray()); var absoluteDircetoryPath = PathUtilities.GetDirectoryName(document.FilePath); var logicalDirectoryPath = PathUtilities.CombineAbsoluteAndRelativePaths(projectRoot, folderPath); if (PathUtilities.PathsEqual(absoluteDircetoryPath, logicalDirectoryPath)) { allDocumentIds = linkedDocumentids.Add(document.Id); return(true); } else { allDocumentIds = default; return(false); } }
public CPSProject( VisualStudioProjectTracker projectTracker, Func <ProjectId, IVsReportExternalErrors> reportExternalErrorCreatorOpt, string projectDisplayName, string projectFilePath, IVsHierarchy hierarchy, string language, Guid projectGuid, string binOutputPath, IServiceProvider serviceProvider, VisualStudioWorkspaceImpl visualStudioWorkspaceOpt, HostDiagnosticUpdateSource hostDiagnosticUpdateSourceOpt, ICommandLineParserService commandLineParserServiceOpt) : base(projectTracker, reportExternalErrorCreatorOpt, projectDisplayName, projectFilePath, hierarchy, language, projectGuid, serviceProvider, visualStudioWorkspaceOpt, hostDiagnosticUpdateSourceOpt, commandLineParserServiceOpt) { if (binOutputPath != null) { // Ensure that binOutputPath is either null or a rooted path. // CPS might provide such invalid paths during initialization or when project is in unrestored state. if (binOutputPath == String.Empty) { binOutputPath = null; } else if (!PathUtilities.IsAbsolute(binOutputPath)) { // Make it a rooted path. var basePath = PathUtilities.IsAbsolute(projectFilePath) ? PathUtilities.GetDirectoryName(projectFilePath) : Path.GetTempPath(); binOutputPath = PathUtilities.CombineAbsoluteAndRelativePaths(basePath, binOutputPath); } } // We need to ensure that the bin output path for the project has been initialized before we hookup the project with the project tracker. SetBinOutputPathAndRelatedData(binOutputPath); // Now hook up the project to the project tracker. projectTracker.AddProject(this); }
public void ResolveMetadataFile1() { string fileName = "f.dll"; string drive = "C"; string dir = @"C:\dir"; string subdir = @"C:\dir\subdir"; string filePath = dir + @"\" + fileName; string subFilePath = subdir + @"\" + fileName; string dotted = subdir + @"\" + ".x.dll"; var fs = new HashSet <string> { filePath, subFilePath, dotted }; var resolver = new VirtualizedRelativePathResolver( existingFullPaths: fs, searchPaths: ImmutableArray.Create <string>(), baseDirectory: subdir); // unqualified file name: var path = resolver.ResolvePath(fileName, baseFilePath: null); Assert.Equal(subFilePath, path); // prefer the base file over base directory: path = resolver.ResolvePath(fileName, baseFilePath: PathUtilities.CombineAbsoluteAndRelativePaths(dir, "foo.csx")); Assert.Equal(filePath, path); path = resolver.ResolvePath(@"\" + fileName, baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(@"/" + fileName, baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(@".", baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(@".\" + fileName, baseFilePath: null); Assert.Equal(subFilePath, path); path = resolver.ResolvePath(@"./" + fileName, baseFilePath: null); Assert.Equal(subFilePath, path); path = resolver.ResolvePath(@".x.dll", baseFilePath: null); Assert.Equal(dotted, path); path = resolver.ResolvePath(@"..", baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(@"..\" + fileName, baseFilePath: null); Assert.Equal(filePath, path); path = resolver.ResolvePath(@"../" + fileName, baseFilePath: null); Assert.Equal(filePath, path); path = resolver.ResolvePath(@"C:\" + fileName, baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(@"C:/" + fileName, baseFilePath: null); Assert.Equal(null, path); path = resolver.ResolvePath(filePath, baseFilePath: null); Assert.Equal(filePath, path); // drive-relative paths not supported: path = resolver.ResolvePath(drive + ":" + fileName, baseFilePath: null); Assert.Equal(null, path); // \abc\def string rooted = filePath.Substring(2); path = resolver.ResolvePath(rooted, null); Assert.Equal(filePath, path); }
// internal for testing internal ImmutableArray <CompletionItem> GetItems(string directoryPath, CancellationToken cancellationToken) { if (!PathUtilities.IsUnixLikePlatform && directoryPath.Length == 1 && directoryPath[0] == '\\') { // The user has typed only "\". In this case, we want to add "\\" to the list. return(ImmutableArray.Create(CreateNetworkRoot())); } var result = ArrayBuilder <CompletionItem> .GetInstance(); var pathKind = PathUtilities.GetPathKind(directoryPath); switch (pathKind) { case PathKind.Empty: // base directory if (_baseDirectoryOpt != null) { result.AddRange(GetItemsInDirectory(_baseDirectoryOpt, cancellationToken)); } // roots if (PathUtilities.IsUnixLikePlatform) { result.AddRange(CreateUnixRoot()); } else { foreach (var drive in GetLogicalDrives()) { result.Add(CreateLogicalDriveItem(drive.TrimEnd(s_windowsDirectorySeparator))); } result.Add(CreateNetworkRoot()); } // entries on search paths foreach (var searchPath in _searchPaths) { result.AddRange(GetItemsInDirectory(searchPath, cancellationToken)); } break; case PathKind.Absolute: case PathKind.RelativeToCurrentDirectory: case PathKind.RelativeToCurrentParent: case PathKind.RelativeToCurrentRoot: var fullDirectoryPath = FileUtilities.ResolveRelativePath(directoryPath, basePath: null, baseDirectory: _baseDirectoryOpt); if (fullDirectoryPath != null) { result.AddRange(GetItemsInDirectory(fullDirectoryPath, cancellationToken)); } else { // invalid path result.Clear(); } break; case PathKind.Relative: // base directory: if (_baseDirectoryOpt != null) { result.AddRange(GetItemsInDirectory(PathUtilities.CombineAbsoluteAndRelativePaths(_baseDirectoryOpt, directoryPath), cancellationToken)); } // search paths: foreach (var searchPath in _searchPaths) { result.AddRange(GetItemsInDirectory(PathUtilities.CombineAbsoluteAndRelativePaths(searchPath, directoryPath), cancellationToken)); } break; case PathKind.RelativeToDriveDirectory: // Paths "C:dir" are not supported, but when the path doesn't include any directory, i.e. "C:", // we return the drive itself. if (directoryPath.Length == 2) { result.Add(CreateLogicalDriveItem(directoryPath)); } break; default: throw ExceptionUtilities.UnexpectedValue(pathKind); } return(result.ToImmutableAndFree()); }
private ImmutableArray <CompletionItem> GetFilesAndDirectories(string path, string basePath) { var result = ImmutableArray.CreateBuilder <CompletionItem>(); var pathKind = PathUtilities.GetPathKind(path); switch (pathKind) { case PathKind.Empty: result.Add(CreateCurrentDirectoryItem()); if (!IsDriveRoot(_fileSystemDiscoveryService.WorkingDirectory)) { result.Add(CreateParentDirectoryItem()); } result.Add(CreateNetworkRoot(_textChangeSpan)); result.AddRange(GetLogicalDrives()); result.AddRange(GetFilesAndDirectoriesInSearchPaths()); break; case PathKind.Absolute: case PathKind.RelativeToCurrentDirectory: case PathKind.RelativeToCurrentParent: case PathKind.RelativeToCurrentRoot: { var fullPath = FileUtilities.ResolveRelativePath( path, basePath, _fileSystemDiscoveryService.WorkingDirectory); if (fullPath != null) { result.AddRange(GetFilesAndDirectoriesInDirectory(fullPath)); // although it is possible to type "." here, it doesn't make any sense to do so: if (!IsDriveRoot(fullPath) && pathKind != PathKind.Absolute) { result.Add(CreateParentDirectoryItem()); } if (path == "\\" && pathKind == PathKind.RelativeToCurrentRoot) { // The user has typed only "\". In this case, we want to add "\\" to // the list. Also, the textChangeSpan needs to be backed up by one // so that it will consume the "\" when "\\" is inserted. result.Add(CreateNetworkRoot(TextSpan.FromBounds(_textChangeSpan.Start - 1, _textChangeSpan.End))); } } else { // invalid path result.Clear(); } } break; case PathKind.Relative: // although it is possible to type "." here, it doesn't make any sense to do so: result.Add(CreateParentDirectoryItem()); foreach (var searchPath in _searchPaths) { var fullPath = PathUtilities.CombineAbsoluteAndRelativePaths(searchPath, path); // search paths are always absolute: Debug.Assert(PathUtilities.IsAbsolute(fullPath)); result.AddRange(GetFilesAndDirectoriesInDirectory(fullPath)); } break; case PathKind.RelativeToDriveDirectory: // these paths are not supported break; default: throw ExceptionUtilities.Unreachable; } return(result.AsImmutable()); }
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); }
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); }
public void ResolveReference() { var expectedProjectJson = @"{ ""dependencies"": { ""A.B.C"": ""1.2"" }, ""frameworks"": { ""net46"": {} } }"; var actualProjectLockJson = @"{ ""locked"": false, ""version"": 1, ""targets"": { "".NETFramework,Version=v4.5"": { }, "".NETFramework,Version=v4.6"": { ""System.Collections/4.0.10"": { ""dependencies"": { ""System.Runtime"": """" }, ""compile"": { ""ref/dotnet/System.Runtime.dll"": {} }, ""runtime"": { ""ref/dotnet/System.Collections.dll"": {} } }, ""System.Diagnostics.Debug/4.0.10"": { ""dependencies"": { ""System.Runtime"": """" }, }, ""System.IO/4.0.10"": { ""dependencies"": {}, ""runtime"": { ""ref/dotnet/System.Runtime.dll"": {}, ""ref/dotnet/System.IO.dll"": {} } } } } }"; using (var directory = new DisposableDirectory(Temp)) { var packagesDirectory = directory.Path; var resolver = new NuGetPackageResolverImpl( packagesDirectory, startInfo => { var arguments = startInfo.Arguments.Split('"'); Assert.Equal(5, arguments.Length); Assert.Equal("restore ", arguments[0]); Assert.Equal("project.json", PathUtilities.GetFileName(arguments[1])); Assert.Equal(" -PackagesDirectory ", arguments[2]); Assert.Equal(packagesDirectory, arguments[3]); Assert.Equal("", arguments[4]); var projectJsonPath = arguments[1]; var actualProjectJson = File.ReadAllText(projectJsonPath); Assert.Equal(expectedProjectJson, actualProjectJson); var projectLockJsonPath = PathUtilities.CombineAbsoluteAndRelativePaths(PathUtilities.GetDirectoryName(projectJsonPath), "project.lock.json"); using (var writer = new StreamWriter(projectLockJsonPath)) { writer.Write(actualProjectLockJson); } }); var actualPaths = resolver.ResolveNuGetPackage("A.B.C/1.2"); AssertEx.SetEqual(actualPaths, PathUtilities.CombineAbsoluteAndRelativePaths(packagesDirectory, PathUtilities.CombinePossiblyRelativeAndRelativePaths("System.Collections/4.0.10", "ref/dotnet/System.Collections.dll")), PathUtilities.CombineAbsoluteAndRelativePaths(packagesDirectory, PathUtilities.CombinePossiblyRelativeAndRelativePaths("System.IO/4.0.10", "ref/dotnet/System.Runtime.dll")), PathUtilities.CombineAbsoluteAndRelativePaths(packagesDirectory, PathUtilities.CombinePossiblyRelativeAndRelativePaths("System.IO/4.0.10", "ref/dotnet/System.IO.dll"))); } }
public void ResolveMetadataFile2() { string fileName = "f.dll"; string dir = @"C:\dir"; string subdir = @"C:\dir\subdir"; string filePath = dir + @"\" + fileName; string subFilePath = subdir + @"\" + fileName; var fs = new HashSet <string> { filePath, subFilePath }; // with no search paths var resolver = new VirtualizedRelativePathResolver( existingFullPaths: fs, baseDirectory: subdir); // using base path var path = resolver.ResolvePath(fileName, baseFilePath: PathUtilities.CombineAbsoluteAndRelativePaths(dir, "foo.csx")); Assert.Equal(filePath, path); // using base dir path = resolver.ResolvePath(fileName, baseFilePath: null); Assert.Equal(subFilePath, path); // search paths var resolverSP = new VirtualizedRelativePathResolver( existingFullPaths: fs, searchPaths: new[] { dir, subdir }.AsImmutableOrNull(), baseDirectory: @"C:\foo"); path = resolverSP.ResolvePath(fileName, baseFilePath: null); Assert.Equal(filePath, path); // null base dir, no search paths var resolverNullBase = new VirtualizedRelativePathResolver( existingFullPaths: fs, baseDirectory: null); // relative path path = resolverNullBase.ResolvePath(fileName, baseFilePath: null); Assert.Null(path); // full path path = resolverNullBase.ResolvePath(filePath, baseFilePath: null); Assert.Equal(filePath, path); // null base dir var resolverNullBaseSP = new VirtualizedRelativePathResolver( existingFullPaths: fs, searchPaths: new[] { dir, subdir }.AsImmutableOrNull(), baseDirectory: null); // relative path path = resolverNullBaseSP.ResolvePath(fileName, baseFilePath: null); Assert.Equal(filePath, path); // full path path = resolverNullBaseSP.ResolvePath(filePath, baseFilePath: null); Assert.Equal(filePath, path); }