// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
namespace ICSharpCode.NRefactory.ConsistencyCheck
{
///
/// Represents a C# project (.csproj file)
///
public class CSharpProject
{
///
/// Parent solution.
///
public readonly Solution Solution;
///
/// Title is the project name as specified in the .sln file.
///
public readonly string Title;
///
/// Name of the output assembly.
///
public readonly string AssemblyName;
///
/// Full path to the .csproj file.
///
public readonly string FileName;
public readonly List Files = new List();
public readonly CompilerSettings CompilerSettings = new CompilerSettings();
///
/// The unresolved type system for this project.
///
public readonly IProjectContent ProjectContent;
///
/// The resolved type system for this project.
/// This field is initialized once all projects have been loaded (in Solution constructor).
///
public ICompilation Compilation;
public CSharpProject(Solution solution, string title, string fileName)
{
// Normalize the file name
fileName = Path.GetFullPath(fileName);
this.Solution = solution;
this.Title = title;
this.FileName = fileName;
// Use MSBuild to open the .csproj
var msbuildProject = new Microsoft.Build.Evaluation.Project(fileName);
// Figure out some compiler settings
this.AssemblyName = msbuildProject.GetPropertyValue("AssemblyName");
this.CompilerSettings.AllowUnsafeBlocks = GetBoolProperty(msbuildProject, "AllowUnsafeBlocks") ?? false;
this.CompilerSettings.CheckForOverflow = GetBoolProperty(msbuildProject, "CheckForOverflowUnderflow") ?? false;
string defineConstants = msbuildProject.GetPropertyValue("DefineConstants");
foreach (string symbol in defineConstants.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries))
this.CompilerSettings.ConditionalSymbols.Add(symbol.Trim());
// Initialize the unresolved type system
IProjectContent pc = new CSharpProjectContent();
pc = pc.SetAssemblyName(this.AssemblyName);
pc = pc.SetProjectFileName(fileName);
pc = pc.SetCompilerSettings(this.CompilerSettings);
// Parse the C# code files
foreach (var item in msbuildProject.GetItems("Compile")) {
var file = new CSharpFile(this, Path.Combine(msbuildProject.DirectoryPath, item.EvaluatedInclude));
Files.Add(file);
}
// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(Files.Select(f => f.UnresolvedTypeSystemForFile));
// Add referenced assemblies:
foreach (string assemblyFile in ResolveAssemblyReferences(msbuildProject)) {
IUnresolvedAssembly assembly = solution.LoadAssembly(assemblyFile);
pc = pc.AddAssemblyReferences(new [] { assembly });
}
// Add project references:
foreach (var item in msbuildProject.GetItems("ProjectReference")) {
string referencedFileName = Path.Combine(msbuildProject.DirectoryPath, item.EvaluatedInclude);
// Normalize the path; this is required to match the name with the referenced project's file name
referencedFileName = Path.GetFullPath(referencedFileName);
pc = pc.AddAssemblyReferences(new[] { new ProjectReference(referencedFileName) });
}
this.ProjectContent = pc;
}
IEnumerable ResolveAssemblyReferences(Microsoft.Build.Evaluation.Project project)
{
// Use MSBuild to figure out the full path of the referenced assemblies
var projectInstance = project.CreateProjectInstance();
projectInstance.SetProperty("BuildingProject", "false");
project.SetProperty("DesignTimeBuild", "true");
projectInstance.Build("ResolveAssemblyReferences", new [] { new ConsoleLogger(LoggerVerbosity.Minimal) });
var items = projectInstance.GetItems("_ResolveAssemblyReferenceResolvedFiles");
string baseDirectory = Path.GetDirectoryName(this.FileName);
var result = items.Select(i => Path.Combine(baseDirectory, i.GetMetadataValue("Identity"))).ToList();
if (!result.Any(t => t.Contains("mscorlib") || t.Contains("System.Runtime")))
result.Add(typeof(object).Assembly.Location);
return result;
}
static bool? GetBoolProperty(Microsoft.Build.Evaluation.Project p, string propertyName)
{
string val = p.GetPropertyValue(propertyName);
bool result;
if (bool.TryParse(val, out result))
return result;
else
return null;
}
public override string ToString()
{
return string.Format("[CSharpProject AssemblyName={0}]", AssemblyName);
}
}
}