提交 07177396 编写于 作者: M Matt Warren

Merge pull request #3690 from mattwar/ProjectFile2

Use command line args to describe options
Microsoft Visual Studio Solution File, Format Version 12.00

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23025.0
MinimumVisualStudioVersion = 10.0.40219.1
......@@ -358,8 +359,8 @@ Global
src\ExpressionEvaluator\CSharp\Source\ResultProvider\CSharpResultProvider.projitems*{bf9dac1e-3a5e-4dc3-bb44-9a64e0d4e9d3}*SharedItemsImports = 4
src\Compilers\Core\SharedCollections\SharedCollections.projitems*{afde6bea-5038-4a4a-a88e-dbd2e4088eed}*SharedItemsImports = 4
src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{fa0e905d-ec46-466d-b7b2-3b5557f9428c}*SharedItemsImports = 4
src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
src\Compilers\Core\SharedCollections\SharedCollections.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{3973b09a-4fbf-44a5-8359-3d22ceb71f71}*SharedItemsImports = 4
src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{bedc5a4a-809e-4017-9cfd-6c8d4e1847f0}*SharedItemsImports = 4
src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{b501a547-c911-4a05-ac6e-274a50dff30e}*SharedItemsImports = 4
......@@ -4823,6 +4824,34 @@ Global
{D874349C-8BB3-4BDC-8535-2D52CCCA1198}.Release|x64.Build.0 = Release|Any CPU
{D874349C-8BB3-4BDC-8535-2D52CCCA1198}.Release|x86.ActiveCfg = Release|Any CPU
{D874349C-8BB3-4BDC-8535-2D52CCCA1198}.Release|x86.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|ARM.ActiveCfg = Debug|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|ARM.Build.0 = Debug|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|x64.ActiveCfg = Debug|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|x64.Build.0 = Debug|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|x86.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodDebug|Any CPU.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodDebug|ARM.ActiveCfg = Debug|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodDebug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodDebug|x64.ActiveCfg = Debug|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodDebug|x86.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodRelease|Any CPU.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodRelease|ARM.ActiveCfg = Release|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodRelease|Mixed Platforms.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodRelease|x64.ActiveCfg = Release|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.DogfoodRelease|x86.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Any CPU.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|ARM.ActiveCfg = Release|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|ARM.Build.0 = Release|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|x64.ActiveCfg = Release|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|x64.Build.0 = Release|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|x86.ActiveCfg = Release|Any CPU
{76242A2D-2600-49DD-8C15-FEA07ECB1842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76242A2D-2600-49DD-8C15-FEA07ECB1842}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76242A2D-2600-49DD-8C15-FEA07ECB1842}.Debug|ARM.ActiveCfg = Debug|Any CPU
......@@ -5577,22 +5606,6 @@ Global
{06ECCF53-B9B8-4CC2-83C0-E308BF645F7F}.Release|x64.Build.0 = Release|Any CPU
{06ECCF53-B9B8-4CC2-83C0-E308BF645F7F}.Release|x86.ActiveCfg = Release|Any CPU
{06ECCF53-B9B8-4CC2-83C0-E308BF645F7F}.Release|x86.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|ARM.ActiveCfg = Debug|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|ARM.Build.0 = Debug|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|x64.ActiveCfg = Debug|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Debug|x64.Build.0 = Debug|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Any CPU.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|ARM.ActiveCfg = Release|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|ARM.Build.0 = Release|ARM
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|x64.ActiveCfg = Release|x64
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -5724,6 +5737,7 @@ Global
{C1930979-C824-496B-A630-70F5369A636F} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9}
{FCFA8808-A1B6-48CC-A1EA-0B8CA8AEDA8E} = {32A48625-F0AD-419D-828B-A50BDABA38EA}
{D874349C-8BB3-4BDC-8535-2D52CCCA1198} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9}
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9}
{3140FE61-0856-4367-9AA3-8081B9A80E35} = {151F6994-AEB3-4B12-B746-2ACFF26C7BBB}
{76242A2D-2600-49DD-8C15-FEA07ECB1842} = {151F6994-AEB3-4B12-B746-2ACFF26C7BBB}
{76242A2D-2600-49DD-8C15-FEA07ECB1843} = {151F6994-AEB3-4B12-B746-2ACFF26C7BBB}
......@@ -5751,6 +5765,5 @@ Global
{2491A9B9-C0A8-49EE-9077-A32DE76E1E94} = {999FBDA2-33DA-4F74-B957-03AC72CCE5EC}
{5CA5F70E-0FDB-467B-B22C-3CD5994F0087} = {999FBDA2-33DA-4F74-B957-03AC72CCE5EC}
{81F048A1-B30A-4E74-9BD3-2655DA1DBEA6} = {999FBDA2-33DA-4F74-B957-03AC72CCE5EC}
{1DFEA9C5-973C-4179-9B1B-0F32288E1EF2} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9}
EndGlobalSection
EndGlobal
......@@ -116,7 +116,7 @@
<Compile Include="CodeGeneration\UsingDirectivesAdder.Rewriter.cs" />
<Compile Include="Composition\CSharpWorkspaceFeatures.cs" />
<Compile Include="Extensions\SemanticModelExtensions.cs" />
<Compile Include="LanguageServices\CSharpHostBuildDataFactory.cs" />
<Compile Include="LanguageServices\CSharpCommandLineParserService.cs" />
<Compile Include="CSharpWorkspaceResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
[ExportLanguageService(typeof(ICommandLineParserService), LanguageNames.CSharp), Shared]
internal sealed class CSharpCommandLineParserService : ICommandLineParserService
{
public CommandLineArguments Parse(IEnumerable<string> arguments, string baseDirectory, bool isInteractive, string sdkDirectory)
{
#if SCRIPTING
var parser = isInteractive ? CSharpCommandLineParser.Interactive : CSharpCommandLineParser.Default;
#else
var parser = CSharpCommandLineParser.Default;
#endif
return parser.Parse(arguments, baseDirectory, sdkDirectory);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
[ExportLanguageService(typeof(ICommandLineArgumentsFactoryService), LanguageNames.CSharp), Shared]
internal sealed class CSharpCommandLineParserFactory : ICommandLineArgumentsFactoryService
{
public CommandLineArguments CreateCommandLineArguments(IEnumerable<string> arguments, string baseDirectory, bool isInteractive, string sdkDirectory)
{
var parser = isInteractive ? CSharpCommandLineParser.Interactive : CSharpCommandLineParser.Default;
return parser.Parse(arguments, baseDirectory, sdkDirectory);
}
}
[ExportLanguageService(typeof(IHostBuildDataFactory), LanguageNames.CSharp), Shared]
internal sealed class CSharpHostBuildDataFactory : IHostBuildDataFactory
{
public HostBuildData Create(HostBuildOptions options)
{
var parseOptions = new CSharpParseOptions(languageVersion: LanguageVersion.CSharp6, documentationMode: DocumentationMode.Parse);
var compilationOptions = new CSharpCompilationOptions(
OutputKind.ConsoleApplication,
xmlReferenceResolver: new XmlFileResolver(options.ProjectDirectory),
sourceReferenceResolver: new SourceFileResolver(ImmutableArray<string>.Empty, options.ProjectDirectory),
metadataReferenceResolver: new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, options.ProjectDirectory),
MetadataFileReferenceProvider.Default),
strongNameProvider: new DesktopStrongNameProvider(ImmutableArray.Create(options.ProjectDirectory, options.OutputDirectory)),
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default);
var warnings = new List<KeyValuePair<string, ReportDiagnostic>>(options.Warnings);
if (options.OutputKind.HasValue)
{
var kind = options.OutputKind.Value;
compilationOptions = compilationOptions.WithOutputKind(kind);
if (compilationOptions.Platform == Platform.AnyCpu32BitPreferred &&
(kind == OutputKind.DynamicallyLinkedLibrary || kind == OutputKind.NetModule || kind == OutputKind.WindowsRuntimeMetadata))
{
compilationOptions = compilationOptions.WithPlatform(Platform.AnyCpu);
}
}
if (!string.IsNullOrEmpty(options.DefineConstants))
{
IEnumerable<Diagnostic> diagnostics;
parseOptions = parseOptions.WithPreprocessorSymbols(CSharpCommandLineParser.ParseConditionalCompilationSymbols(options.DefineConstants, out diagnostics));
}
if (options.DocumentationFile != null)
{
parseOptions = parseOptions.WithDocumentationMode(!string.IsNullOrEmpty(options.DocumentationFile) ? DocumentationMode.Diagnose : DocumentationMode.Parse);
}
if (options.LanguageVersion != null)
{
var languageVersion = CompilationOptionsConversion.GetLanguageVersion(options.LanguageVersion);
if (languageVersion.HasValue)
{
parseOptions = parseOptions.WithLanguageVersion(languageVersion.Value);
}
}
if (!string.IsNullOrEmpty(options.PlatformWith32BitPreference))
{
Platform platform;
if (Enum.TryParse<Platform>(options.PlatformWith32BitPreference, true, out platform))
{
if (platform == Platform.AnyCpu &&
compilationOptions.OutputKind != OutputKind.DynamicallyLinkedLibrary &&
compilationOptions.OutputKind != OutputKind.NetModule &&
compilationOptions.OutputKind != OutputKind.WindowsRuntimeMetadata)
{
platform = Platform.AnyCpu32BitPreferred;
}
compilationOptions = compilationOptions.WithPlatform(platform);
}
}
if (options.AllowUnsafeBlocks.HasValue)
{
compilationOptions = compilationOptions.WithAllowUnsafe(options.AllowUnsafeBlocks.Value);
}
if (options.CheckForOverflowUnderflow.HasValue)
{
compilationOptions = compilationOptions.WithOverflowChecks(options.CheckForOverflowUnderflow.Value);
}
if (options.DelaySign != null)
{
bool delaySignExplicitlySet = options.DelaySign.Item1;
bool delaySign = options.DelaySign.Item2;
compilationOptions = compilationOptions.WithDelaySign(delaySignExplicitlySet ? delaySign : (bool?)null);
}
if (!string.IsNullOrEmpty(options.ApplicationConfiguration))
{
var appConfigPath = FileUtilities.ResolveRelativePath(options.ApplicationConfiguration, options.ProjectDirectory);
try
{
using (var appConfigStream = PortableShim.FileStream.Create(appConfigPath, PortableShim.FileMode.Open, PortableShim.FileAccess.Read))
{
compilationOptions = compilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream));
}
}
catch (Exception)
{
}
}
if (!string.IsNullOrEmpty(options.KeyContainer))
{
compilationOptions = compilationOptions.WithCryptoKeyContainer(options.KeyContainer);
}
if (!string.IsNullOrEmpty(options.KeyFile))
{
var fullPath = FileUtilities.ResolveRelativePath(options.KeyFile, options.ProjectDirectory);
compilationOptions = compilationOptions.WithCryptoKeyFile(fullPath);
}
if (!string.IsNullOrEmpty(options.MainEntryPoint))
{
compilationOptions = compilationOptions.WithMainTypeName(options.MainEntryPoint);
}
if (!string.IsNullOrEmpty(options.ModuleAssemblyName))
{
compilationOptions = compilationOptions.WithModuleName(options.ModuleAssemblyName);
}
if (options.Optimize.HasValue)
{
compilationOptions = compilationOptions.WithOptimizationLevel(options.Optimize.Value ? OptimizationLevel.Release : OptimizationLevel.Debug);
}
if (!string.IsNullOrEmpty(options.Platform))
{
Platform plat;
if (Enum.TryParse<Platform>(options.Platform, ignoreCase: true, result: out plat))
{
compilationOptions = compilationOptions.WithPlatform(plat);
}
}
// Get options from the ruleset file, if any.
if (!string.IsNullOrEmpty(options.RuleSetFile))
{
var fullPath = FileUtilities.ResolveRelativePath(options.RuleSetFile, options.ProjectDirectory);
Dictionary<string, ReportDiagnostic> specificDiagnosticOptions;
var generalDiagnosticOption = RuleSet.GetDiagnosticOptionsFromRulesetFile(fullPath, out specificDiagnosticOptions);
compilationOptions = compilationOptions.WithGeneralDiagnosticOption(generalDiagnosticOption);
warnings.AddRange(specificDiagnosticOptions);
}
if (options.WarningsAsErrors.HasValue)
{
compilationOptions = compilationOptions.WithGeneralDiagnosticOption(options.WarningsAsErrors.Value ? ReportDiagnostic.Error : ReportDiagnostic.Default);
}
if (options.WarningLevel.HasValue)
{
compilationOptions = compilationOptions.WithWarningLevel(options.WarningLevel.Value);
}
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(warnings);
return new HostBuildData(
parseOptions,
compilationOptions);
}
}
}
......@@ -30,8 +30,8 @@ public static ProjectInfo CreateProjectInfo(string projectName, string language,
throw new ArgumentException(WorkspacesResources.UnrecognizedLanguageName);
}
var commandLineArgumentsFactory = languageServices.GetRequiredService<ICommandLineArgumentsFactoryService>();
var commandLineArguments = commandLineArgumentsFactory.CreateCommandLineArguments(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
var commandLineParser = languageServices.GetRequiredService<ICommandLineParserService>();
var commandLineArguments = commandLineParser.Parse(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
// TODO (tomat): to match csc.exe/vbc.exe we should use CommonCommandLineCompiler.ExistingReferencesResolver to deal with #r's
var referenceResolver = new MetadataFileReferenceResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
......
......@@ -11,11 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class CSharpProjectFileLoader : ProjectFileLoader
{
private readonly HostWorkspaceServices _workspaceServices;
public CSharpProjectFileLoader(HostWorkspaceServices workspaceServices)
public CSharpProjectFileLoader()
{
_workspaceServices = workspaceServices;
}
public override string Language
......@@ -23,19 +20,9 @@ public override string Language
get { return LanguageNames.CSharp; }
}
public IHostBuildDataFactory MSBuildHost
{
get { return _workspaceServices.GetLanguageServices(Language).GetService<IHostBuildDataFactory>(); }
}
public ICommandLineArgumentsFactoryService CommandLineArgumentsFactoryService
{
get { return _workspaceServices.GetLanguageServices(Language).GetService<ICommandLineArgumentsFactoryService>(); }
}
protected override ProjectFile CreateProjectFile(MSB.Evaluation.Project loadedProject)
{
return new CSharpProjectFile(this, loadedProject, _workspaceServices.GetService<IMetadataService>(), _workspaceServices.GetService<IAnalyzerService>());
return new CSharpProjectFile(this, loadedProject);
}
}
}
......@@ -17,7 +17,7 @@ internal class CSharpProjectFileLoaderFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
return new CSharpProjectFileLoader(languageServices.WorkspaceServices);
return new CSharpProjectFileLoader();
}
}
}
\ No newline at end of file
......@@ -20,6 +20,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Runtime.InteropServices;
namespace Microsoft.CodeAnalysis.MSBuild
{
......@@ -631,8 +632,8 @@ private async Task<ProjectId> GetOrLoadProjectAsync(string projectFilePath, IPro
private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectFileLoader loader, bool preferMetadata, Dictionary<ProjectId, ProjectInfo> loadedProjects, CancellationToken cancellationToken)
{
System.Diagnostics.Debug.Assert(projectFilePath != null);
System.Diagnostics.Debug.Assert(loader != null);
Debug.Assert(projectFilePath != null);
Debug.Assert(loader != null);
var projectId = this.GetOrCreateProjectId(projectFilePath);
......@@ -641,6 +642,10 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
var projectFile = await loader.LoadProjectFileAsync(projectFilePath, _properties, cancellationToken).ConfigureAwait(false);
var projectFileInfo = await projectFile.GetProjectFileInfoAsync(cancellationToken).ConfigureAwait(false);
var projectDirectory = Path.GetDirectoryName(projectFilePath);
var outputFilePath = projectFileInfo.OutputFilePath;
var outputDirectory = Path.GetDirectoryName(outputFilePath);
VersionStamp version;
if (!string.IsNullOrEmpty(projectFilePath) && File.Exists(projectFilePath))
{
......@@ -651,11 +656,37 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
version = VersionStamp.Create();
}
// Documents
// translate information from command line args
var commandLineParser = this.Services.GetLanguageServices(loader.Language).GetService<ICommandLineParserService>();
var metadataService = this.Services.GetService<IMetadataService>();
var analyzerService = this.Services.GetService<IAnalyzerService>();
var commandLineArgs = commandLineParser.Parse(
arguments: projectFileInfo.CommandLineArgs,
baseDirectory: projectDirectory,
isInteractive: false,
sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
var resolver = new MetadataFileReferenceResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory);
var metadataReferences = commandLineArgs.ResolveMetadataReferences(new AssemblyReferenceResolver(resolver, metadataService.GetProvider()));
var analyzerLoader = analyzerService.GetLoader();
foreach (var path in commandLineArgs.AnalyzerReferences.Select(r => r.FilePath))
{
analyzerLoader.AddDependencyLocation(path);
}
var analyzerReferences = commandLineArgs.ResolveAnalyzerReferences(analyzerLoader);
var defaultEncoding = commandLineArgs.Encoding;
// docs & additional docs
var docFileInfos = projectFileInfo.Documents.ToImmutableArrayOrEmpty();
CheckDocuments(docFileInfos, projectFilePath, projectId);
var additionalDocFileInfos = projectFileInfo.AdditionalDocuments.ToImmutableArrayOrEmpty();
Encoding defaultEncoding = GetDefaultEncoding(projectFileInfo.CodePage);
// check for duplicate documents
var allDocFileInfos = docFileInfos.AddRange(additionalDocFileInfos);
CheckDocuments(allDocFileInfos, projectFilePath, projectId);
var docs = new List<DocumentInfo>();
foreach (var docFileInfo in docFileInfos)
......@@ -675,7 +706,7 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
}
var additionalDocs = new List<DocumentInfo>();
foreach (var docFileInfo in projectFileInfo.AdditionalDocuments)
foreach (var docFileInfo in additionalDocFileInfos)
{
string name;
ImmutableArray<string> folders;
......@@ -695,13 +726,11 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
var resolvedReferences = await this.ResolveProjectReferencesAsync(
projectId, projectFilePath, projectFileInfo.ProjectReferences, preferMetadata, loadedProjects, cancellationToken).ConfigureAwait(false);
var metadataReferences = projectFileInfo.MetadataReferences
.Concat(resolvedReferences.MetadataReferences);
var outputFilePath = projectFileInfo.OutputFilePath;
var assemblyName = projectFileInfo.AssemblyName;
// add metadata references for project refs converted to metadata refs
metadataReferences = metadataReferences.Concat(resolvedReferences.MetadataReferences);
// if the project file loader couldn't figure out an assembly name, make one using the project's file path.
var assemblyName = commandLineArgs.CompilationName;
if (string.IsNullOrWhiteSpace(assemblyName))
{
assemblyName = Path.GetFileNameWithoutExtension(projectFilePath);
......@@ -713,6 +742,24 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
}
}
// make sure that doc-comments at least get parsed.
var parseOptions = commandLineArgs.ParseOptions;
if (parseOptions.DocumentationMode == DocumentationMode.None)
{
parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.Parse);
}
// add all the extra options that are really behavior overrides
var compOptions = commandLineArgs.CompilationOptions
.WithXmlReferenceResolver(new XmlFileResolver(projectDirectory))
.WithSourceReferenceResolver(new SourceFileResolver(ImmutableArray<string>.Empty, projectDirectory))
.WithMetadataReferenceResolver(
new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, projectDirectory),
MetadataFileReferenceProvider.Default))
.WithStrongNameProvider(new DesktopStrongNameProvider(ImmutableArray.Create(projectDirectory, outputFilePath)))
.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
loadedProjects.Add(
projectId,
ProjectInfo.Create(
......@@ -723,12 +770,12 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
loader.Language,
projectFilePath,
outputFilePath,
projectFileInfo.CompilationOptions,
projectFileInfo.ParseOptions,
docs,
resolvedReferences.ProjectReferences,
metadataReferences,
analyzerReferences: projectFileInfo.AnalyzerReferences,
compilationOptions: compOptions,
parseOptions: parseOptions,
documents: docs,
projectReferences: resolvedReferences.ProjectReferences,
metadataReferences: metadataReferences,
analyzerReferences: analyzerReferences,
additionalDocuments: additionalDocs,
isSubmission: false,
hostObjectType: null));
......@@ -736,25 +783,6 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
return projectId;
}
private static Encoding GetDefaultEncoding(int codePage)
{
// If no CodePage was specified in the project file, then the FileTextLoader will
// attempt to use UTF8 before falling back on Encoding.Default.
if (codePage == 0)
{
return null;
}
try
{
return Encoding.GetEncoding(codePage);
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
private static readonly char[] s_directorySplitChars = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
private static void GetDocumentNameAndFolders(string logicalPath, out string name, out ImmutableArray<string> folders)
......
......@@ -36,11 +36,6 @@ internal interface IProjectFile
/// </summary>
string GetDocumentExtension(SourceCodeKind kind);
/// <summary>
/// Gets a specific project file property.
/// </summary>
string GetPropertyValue(string name);
/// <summary>
/// Add a source document to a project file.
/// </summary>
......
......@@ -23,19 +23,9 @@ internal sealed class ProjectFileInfo
public string AssemblyName { get; }
/// <summary>
/// The compilation options for this project.
/// The command line args used to compile the project.
/// </summary>
public CompilationOptions CompilationOptions { get; }
/// <summary>
/// The parse options for this project.
/// </summary>
public ParseOptions ParseOptions { get; }
/// <summary>
/// The codepage for this project.
/// </summary>
public int CodePage { get; }
public IReadOnlyList<string> CommandLineArgs { get; }
/// <summary>
/// The source documents.
......@@ -52,38 +42,20 @@ internal sealed class ProjectFileInfo
/// </summary>
public IReadOnlyList<ProjectFileReference> ProjectReferences { get; }
/// <summary>
/// References to other metadata files; libraries and executables.
/// </summary>
public IReadOnlyList<MetadataReference> MetadataReferences { get; }
/// <summary>
/// References to analyzer assembly files; contains diagnostic analyzers.
/// </summary>
public IReadOnlyList<AnalyzerReference> AnalyzerReferences { get; }
public ProjectFileInfo(
string outputPath,
string assemblyName,
CompilationOptions compilationOptions,
ParseOptions parseOptions,
int codePage,
IEnumerable<string> commandLineArgs,
IEnumerable<DocumentFileInfo> documents,
IEnumerable<DocumentFileInfo> additionalDocuments,
IEnumerable<ProjectFileReference> projectReferences,
IEnumerable<MetadataReference> metadataReferences,
IEnumerable<AnalyzerReference> analyzerReferences)
IEnumerable<ProjectFileReference> projectReferences)
{
this.OutputFilePath = outputPath;
this.AssemblyName = assemblyName;
this.CompilationOptions = compilationOptions;
this.ParseOptions = parseOptions;
this.CodePage = codePage;
this.CommandLineArgs = commandLineArgs.ToImmutableArrayOrEmpty();
this.Documents = documents.ToImmutableReadOnlyListOrEmpty();
this.AdditionalDocuments = additionalDocuments.ToImmutableReadOnlyListOrEmpty();
this.AdditionalDocuments = additionalDocuments.ToImmutableArrayOrEmpty();
this.ProjectReferences = projectReferences.ToImmutableReadOnlyListOrEmpty();
this.MetadataReferences = metadataReferences.ToImmutableReadOnlyListOrEmpty();
this.AnalyzerReferences = analyzerReferences.ToImmutableReadOnlyListOrEmpty();
}
}
}
......@@ -14,7 +14,7 @@ internal class VisualBasicProjectFileLoaderFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
return new VisualBasicProjectFileLoader(languageServices.WorkspaceServices);
return new VisualBasicProjectFileLoader();
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis
{
internal sealed class HostBuildOptions
{
public string ProjectDirectory { get; set; }
public string OutputDirectory { get; set; }
public string DefineConstants { get; set; }
public string DocumentationFile { get; set; }
public string LanguageVersion { get; set; }
public string PlatformWith32BitPreference { get; set; }
public string ApplicationConfiguration { get; set; }
public string KeyContainer { get; set; }
public string KeyFile { get; set; }
public string MainEntryPoint { get; set; }
public string ModuleAssemblyName { get; set; }
public string Platform { get; set; }
public string RuleSetFile { get; set; }
public string OptionCompare { get; set; }
public string OptionStrict { get; set; }
public string RootNamespace { get; set; }
public string VBRuntime { get; set; }
public bool? AllowUnsafeBlocks { get; set; }
public bool? CheckForOverflowUnderflow { get; set; }
public bool? Optimize { get; set; }
public bool? WarningsAsErrors { get; set; }
public bool? NoWarnings { get; set; }
public bool? OptionExplicit { get; set; }
public bool? OptionInfer { get; set; }
public int? WarningLevel { get; set; }
public OutputKind? OutputKind { get; set; }
public Tuple<bool, bool> DelaySign { get; set; }
public List<string> GlobalImports { get; set; }
public Dictionary<string, ReportDiagnostic> Warnings { get; set; }
internal HostBuildOptions()
{
Warnings = new Dictionary<string, ReportDiagnostic>();
GlobalImports = new List<string>();
}
}
internal sealed class HostBuildData
{
internal readonly ParseOptions ParseOptions;
internal readonly CompilationOptions CompilationOptions;
internal HostBuildData(ParseOptions parseOptions, CompilationOptions compilationOptions)
{
ParseOptions = parseOptions;
CompilationOptions = compilationOptions;
}
}
internal interface IHostBuildDataFactory : ILanguageService
{
HostBuildData Create(HostBuildOptions options);
}
}
......@@ -4,8 +4,8 @@
namespace Microsoft.CodeAnalysis.Host
{
internal interface ICommandLineArgumentsFactoryService : ILanguageService
internal interface ICommandLineParserService : ILanguageService
{
CommandLineArguments CreateCommandLineArguments(IEnumerable<string> arguments, string baseDirectory, bool isInteractive, string sdkDirectory);
CommandLineArguments Parse(IEnumerable<string> arguments, string baseDirectory, bool isInteractive, string sdkDirectory);
}
}
......@@ -406,7 +406,6 @@
<Compile Include="Log\Logger.LogBlock.cs" />
<Compile Include="Log\LogMessage.cs" />
<Compile Include="Log\WorkspaceErrorLogger.cs" />
<Compile Include="HostBuild.cs" />
<Compile Include="Rename\TokenRenameInfo.cs" />
<Compile Include="Serialization\AssemblySerializationInfoService.cs" />
<Compile Include="Serialization\IAssemblySerializationInfoService.cs" />
......@@ -580,7 +579,7 @@
<Compile Include="Utilities\ImmutableArrayExtensions.cs" />
<Compile Include="Utilities\ObjectPools\PooledObject.cs" />
<Compile Include="Workspace\Host\Caching\IWorkspaceCacheService.cs" />
<Compile Include="Workspace\Host\CommandLineArgumentsFactory\ICommandLineArgumentsFactoryService.cs" />
<Compile Include="Workspace\Host\CommandLine\ICommandLineParserService.cs" />
<Compile Include="Workspace\Host\HostContext\HostContextService.cs" />
<Compile Include="Workspace\Host\HostContext\IHostContextService.cs" />
<Compile Include="Workspace\Host\Mef\ILanguagesMetadata.cs" />
......
......@@ -1563,6 +1563,13 @@ public void TestCompilationOptions_VisualBasic_OptionStrict_On()
public void TestCompilationOptions_VisualBasic_OptionStrict_Off()
{
CreateVBFilesWith("OptionStrict", "Off");
AssertVBOptions(Microsoft.CodeAnalysis.VisualBasic.OptionStrict.Off, options => options.OptionStrict);
}
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public void TestCompilationOptions_VisualBasic_OptionStrict_Custom()
{
CreateVBFilesWith("OptionStrict", "Custom");
AssertVBOptions(Microsoft.CodeAnalysis.VisualBasic.OptionStrict.Custom, options => options.OptionStrict);
}
......
......@@ -200,7 +200,7 @@
<Compile Include="Formatting\Rules\StructuredTriviaFormattingRule.vb" />
<Compile Include="Formatting\VisualBasicSyntaxFormattingService.vb" />
<Compile Include="LanguageServices\VisualBasicCompilationFactoryService.vb" />
<Compile Include="LanguageServices\VisualBasicHostBuildDataFactory.vb" />
<Compile Include="LanguageServices\VisualBasicCommandLineParserService.vb" />
<Compile Include="LanguageServices\VisualBasicSemanticFactsService.vb" />
<Compile Include="LanguageServices\VisualBasicSymbolDeclarationService.vb" />
<Compile Include="LanguageServices\VisualBasicSyntaxFactsService.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Linq
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic
<ExportLanguageService(GetType(ICommandLineParserService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicCommandLineArgumentsFactoryService
Implements ICommandLineParserService
Public Function Parse(arguments As IEnumerable(Of String), baseDirectory As String, isInteractive As Boolean, sdkDirectory As String) As CommandLineArguments Implements ICommandLineParserService.Parse
#If SCRIPTING Then
Dim parser = If(isInteractive, VisualBasicCommandLineParser.Interactive, VisualBasicCommandLineParser.Default)
#Else
Dim parser = VisualBasicCommandLineParser.Default
#End If
Return parser.Parse(arguments, baseDirectory, sdkDirectory)
End Function
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Linq
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic
<ExportLanguageService(GetType(ICommandLineArgumentsFactoryService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicCommandLineArgumentsFactoryService
Implements ICommandLineArgumentsFactoryService
Public Function CreateCommandLineArguments(arguments As IEnumerable(Of String), baseDirectory As String, isInteractive As Boolean, sdkDirectory As String) As CommandLineArguments Implements ICommandLineArgumentsFactoryService.CreateCommandLineArguments
Dim parser = If(isInteractive, VisualBasicCommandLineParser.Interactive, VisualBasicCommandLineParser.Default)
Return parser.Parse(arguments, baseDirectory, sdkDirectory)
End Function
End Class
<ExportLanguageService(GetType(IHostBuildDataFactory), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicHostBuildDataFactory
Implements IHostBuildDataFactory
Public Function Create(options As HostBuildOptions) As HostBuildData Implements IHostBuildDataFactory.Create
Dim parseOptions = VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.Parse)
Dim compilationOptions = New VisualBasicCompilationOptions(OutputKind.ConsoleApplication,
xmlReferenceResolver:=New XmlFileResolver(options.ProjectDirectory),
sourceReferenceResolver:=New SourceFileResolver(ImmutableArray(Of String).Empty, options.ProjectDirectory),
metadataReferenceResolver:=New AssemblyReferenceResolver(
New MetadataFileReferenceResolver(ImmutableArray(Of String).Empty, options.ProjectDirectory),
MetadataFileReferenceProvider.Default),
strongNameProvider:=New DesktopStrongNameProvider(ImmutableArray.Create(Of String)(options.ProjectDirectory, options.OutputDirectory)),
assemblyIdentityComparer:=DesktopAssemblyIdentityComparer.Default)
If Not String.IsNullOrEmpty(options.PlatformWith32BitPreference) Then
Dim plat As Platform
If [Enum].TryParse(options.PlatformWith32BitPreference, True, plat) Then
Dim outputKind = compilationOptions.OutputKind
If plat = Platform.AnyCpu AndAlso outputKind <> OutputKind.DynamicallyLinkedLibrary AndAlso outputKind <> OutputKind.NetModule AndAlso outputKind <> OutputKind.WindowsRuntimeMetadata Then
plat = Platform.AnyCpu32BitPreferred
End If
compilationOptions = compilationOptions.WithPlatform(plat)
End If
End If
Dim warnings = New Dictionary(Of String, ReportDiagnostic)()
If options.OutputKind.HasValue Then
Dim _outputKind = options.OutputKind.Value
compilationOptions = compilationOptions.WithOutputKind(_outputKind)
If compilationOptions.Platform = Platform.AnyCpu32BitPreferred AndAlso
(_outputKind = OutputKind.DynamicallyLinkedLibrary Or _outputKind = OutputKind.NetModule Or _outputKind = OutputKind.WindowsRuntimeMetadata) Then
compilationOptions = compilationOptions.WithPlatform(Platform.AnyCpu)
End If
End If
If Not String.IsNullOrEmpty(options.DefineConstants) Then
Dim errors As IEnumerable(Of Diagnostic) = Nothing
parseOptions = parseOptions.WithPreprocessorSymbols(VisualBasicCommandLineParser.ParseConditionalCompilationSymbols(options.DefineConstants, errors))
End If
If options.DelaySign IsNot Nothing Then
compilationOptions = compilationOptions.WithDelaySign(options.DelaySign.Item1)
End If
If Not String.IsNullOrEmpty(options.DocumentationFile) Then
parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.Diagnose)
Else
parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.Parse)
End If
If options.GlobalImports.Count > 0 Then
Dim e = options.GlobalImports.Select(Function(item) GlobalImport.Parse(item)).AsImmutable()
compilationOptions = compilationOptions.WithGlobalImports(e)
End If
If Not String.IsNullOrEmpty(options.KeyContainer) Then
compilationOptions = compilationOptions.WithCryptoKeyContainer(options.KeyContainer)
End If
If Not String.IsNullOrEmpty(options.KeyFile) Then
compilationOptions = compilationOptions.WithCryptoKeyFile(options.KeyFile)
End If
If Not String.IsNullOrEmpty(options.MainEntryPoint) AndAlso options.MainEntryPoint <> "Sub Main" Then
compilationOptions = compilationOptions.WithMainTypeName(options.MainEntryPoint)
End If
If options.NoWarnings.HasValue Then
compilationOptions = compilationOptions.WithGeneralDiagnosticOption(If(options.NoWarnings.Value, ReportDiagnostic.Suppress, ReportDiagnostic.Warn))
End If
If options.Optimize.HasValue Then
compilationOptions = compilationOptions.WithOptimizationLevel(If(options.Optimize, OptimizationLevel.Release, OptimizationLevel.Debug))
End If
If Not String.IsNullOrEmpty(options.OptionCompare) Then
compilationOptions = compilationOptions.WithOptionCompareText(options.OptionCompare = "Text")
End If
If options.OptionExplicit.HasValue Then
compilationOptions = compilationOptions.WithOptionExplicit(options.OptionExplicit.Value)
End If
If Not String.IsNullOrEmpty(options.OptionStrict) Then
Dim _optionStrict As OptionStrict = OptionStrict.Custom
If TryGetOptionStrict(options.OptionStrict, _optionStrict) Then
compilationOptions = compilationOptions.WithOptionStrict(_optionStrict)
End If
End If
If Not String.IsNullOrEmpty(options.Platform) Then
Dim plat As Platform
If [Enum].TryParse(options.Platform, plat) Then
compilationOptions = compilationOptions.WithPlatform(plat)
End If
End If
If options.CheckForOverflowUnderflow.HasValue Then
compilationOptions = compilationOptions.WithOverflowChecks(options.CheckForOverflowUnderflow.Value)
End If
If Not String.IsNullOrEmpty(options.RootNamespace) Then
compilationOptions = compilationOptions.WithRootNamespace(options.RootNamespace)
End If
If Not String.IsNullOrEmpty(options.RuleSetFile) Then
Dim fullPath = FileUtilities.ResolveRelativePath(options.RuleSetFile, options.ProjectDirectory)
Dim specificDiagnosticOptions As Dictionary(Of String, ReportDiagnostic) = Nothing
Dim generalDiagnosticOption = RuleSet.GetDiagnosticOptionsFromRulesetFile(fullPath, specificDiagnosticOptions)
compilationOptions = compilationOptions.WithGeneralDiagnosticOption(generalDiagnosticOption)
warnings.AddRange(specificDiagnosticOptions)
End If
If options.WarningsAsErrors.HasValue Then
compilationOptions = compilationOptions.WithGeneralDiagnosticOption(If(options.WarningsAsErrors.Value, ReportDiagnostic.Error, ReportDiagnostic.Warn))
End If
If options.OptionInfer.HasValue Then
compilationOptions = compilationOptions.WithOptionInfer(options.OptionInfer.Value)
End If
If options.VBRuntime = "Embed" Then
compilationOptions = compilationOptions.WithEmbedVbCoreRuntime(True)
End If
If Not String.IsNullOrEmpty(options.LanguageVersion) Then
Dim version As Integer
If Int32.TryParse(options.LanguageVersion, version) Then
Dim lv As LanguageVersion = CType(version, LanguageVersion)
If [Enum].IsDefined(GetType(LanguageVersion), lv) Then
parseOptions = parseOptions.WithLanguageVersion(lv)
End If
End If
End If
parseOptions = parseOptions.WithPreprocessorSymbols(AddPredefinedPreprocessorSymbols(compilationOptions.OutputKind, parseOptions.PreprocessorSymbols))
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(warnings)
Return New HostBuildData(parseOptions, compilationOptions)
End Function
Private Shared Function TryGetOptionStrict(text As String, ByRef optionStrictType As OptionStrict) As Boolean
If text = "On" Then
optionStrictType = OptionStrict.On
Return True
ElseIf text = "Off" OrElse text = "Custom" Then
optionStrictType = OptionStrict.Custom
Return True
Else
Return False
End If
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册