diff options
Diffstat (limited to 'main/src/core/MonoDevelop.Core')
21 files changed, 353 insertions, 225 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs index 7b49c3be82..e6d4a4b32d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs @@ -333,6 +333,10 @@ namespace MonoDevelop.Core.Assemblies get { return new TargetFrameworkMoniker ("4.7.1"); } } + public static TargetFrameworkMoniker NET_4_7_2 { + get { return new TargetFrameworkMoniker ("4.7.2"); } + } + public static TargetFrameworkMoniker PORTABLE_4_0 { get { return new TargetFrameworkMoniker (ID_PORTABLE, "4.0", "Profile1"); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs index c0e4238cb8..d48d076f05 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs @@ -143,6 +143,14 @@ namespace MonoDevelop.Core }
}
+ [Pure]
+ internal bool HasFileName (string name) + { + return fileName.Length > name.Length + && fileName.EndsWith (name, PathComparison) + && fileName [fileName.Length - name.Length - 1] == Path.DirectorySeparatorChar; + }
+
public string Extension {
get {
return Path.GetExtension (fileName);
@@ -153,8 +161,27 @@ namespace MonoDevelop.Core public bool HasExtension (string extension) { return fileName.Length > extension.Length - && fileName.EndsWith (extension, PathComparison) - && fileName[fileName.Length - extension.Length - 1] != Path.PathSeparator; + && (extension == string.Empty + ? HasNoExtension (fileName) + : fileName.EndsWith (extension, PathComparison) && fileName [fileName.Length - extension.Length] == '.'); + + static bool HasNoExtension (string path) + { + // Look for the last dot that's after the last path separator + for (int i = path.Length - 1; i >= 0; --i) { + var ch = path [i]; + if (ch == '.') { + // Check if it's the dot is the last character + // if it is, then we have no extension + return i == path.Length - 1; + } + + if (ch == Path.DirectorySeparatorChar) + return true; + } + + return true; + } }
public string FileNameWithoutExtension {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs index 18d9d0e167..13d5beeaae 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs @@ -45,7 +45,7 @@ namespace MonoDevelop.Projects.Extensions Project project = null; if (!string.IsNullOrEmpty (fileName)) { - p = await MSBuildProject.LoadAsync (fileName); + p = await MSBuildProject.LoadAsync (fileName).ConfigureAwait (false); if (ctx != null && ctx.Solution != null) { p.EngineManager = ctx.Solution.MSBuildEngineManager; p.SolutionDirectory = ctx.Solution.ItemDirectory; @@ -53,7 +53,7 @@ namespace MonoDevelop.Projects.Extensions var migrators = MSBuildProjectService.GetMigrableFlavors (p.ProjectTypeGuids); if (migrators.Count > 0) - await MSBuildProjectService.MigrateFlavors (monitor, fileName, Guid, p, migrators); + await MSBuildProjectService.MigrateFlavors (monitor, fileName, Guid, p, migrators).ConfigureAwait (false); var unsupporedFlavor = p.ProjectTypeGuids.FirstOrDefault (fid => !MSBuildProjectService.IsKnownFlavorGuid (fid) && !MSBuildProjectService.IsKnownTypeGuid (fid)); if (unsupporedFlavor != null) { @@ -72,7 +72,7 @@ namespace MonoDevelop.Projects.Extensions } if (project == null) - project = await base.CreateSolutionItem (monitor, ctx, fileName) as Project; + project = await base.CreateSolutionItem (monitor, ctx, fileName).ConfigureAwait(false) as Project; if (project == null) throw new InvalidOperationException ("Project node type is not a subclass of MonoDevelop.Projects.Project"); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs index 46fa87c880..3cd16adde0 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs @@ -99,7 +99,7 @@ namespace MonoDevelop.Projects.Extensions if (typeof(SolutionItemFactory).IsAssignableFrom (ItemType)) { if (factory == null) factory = (SolutionItemFactory)Activator.CreateInstance (ItemType); - item = await factory.CreateItem (fileName, Guid); + item = await factory.CreateItem (fileName, Guid).ConfigureAwait (false); } else item = MSBuildProjectService.CreateUninitializedInstance (ItemType); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs index e821b48bf6..a22fc426c5 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs @@ -850,7 +850,7 @@ namespace MonoDevelop.Projects.MSBuild static bool IsWildcardInclude (string include) { - return include.IndexOf ('*') != -1; + return include.IndexOfAny (wildcards) != -1; } IEnumerable<MSBuildItemEvaluated> ExpandWildcardFilePath (ProjectInfo pinfo, MSBuildEvaluationContext context, MSBuildItem sourceItem, string path, Regex directoryExcludeRegex) @@ -1018,7 +1018,7 @@ namespace MonoDevelop.Projects.MSBuild return it; } - static char[] wildcards = { '*', '%' }; + static char[] wildcards = { '*', '?' }; void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildProperty prop) { @@ -1174,7 +1174,7 @@ namespace MonoDevelop.Projects.MSBuild var fileName = Path.GetFileName (path); - if (fileName.IndexOfAny (new [] { '*', '?' }) == -1) { + if (fileName.IndexOfAny (wildcards) == -1) { // Not a wildcard. Keep searching if the file doesn't exist. var result = File.Exists (path) ? new [] { path } : null; keepSearching = result == null; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs index 94ea9abfa3..e7626bece3 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs @@ -614,10 +614,6 @@ namespace MonoDevelop.Projects.MSBuild if (memberName.Length == 0) return false; - var member = ResolveMember (type, memberName.ToString (), instance == null); - if (member == null || member.Length == 0) - return false; - if (j < str.Length && str[j] == '(') { // It is a method invocation object [] parameterValues; @@ -625,6 +621,10 @@ namespace MonoDevelop.Projects.MSBuild if (!EvaluateParameters (str, ref j, out parameterValues)) return false; + var member = ResolveMember (type, memberName.ToString (), instance == null, MemberTypes.Method); + if (member == null || member.Length == 0) + return false; + if (!EvaluateMethod (str, member, instance, parameterValues, out val)) return false; @@ -634,6 +634,10 @@ namespace MonoDevelop.Projects.MSBuild } else { // It has to be a property or field try { + var member = ResolveMember (type, memberName.ToString (), instance == null, MemberTypes.Property | MemberTypes.Field); + if (member == null || member.Length == 0) + return false; + if (member[0] is PropertyInfo) val = ((PropertyInfo)member[0]).GetValue (instance); else if (member[0] is FieldInfo) @@ -683,7 +687,7 @@ namespace MonoDevelop.Projects.MSBuild internal bool EvaluateMember (ReadOnlySpan<char> str, Type type, string memberName, object instance, object [] parameterValues, out object val) { val = null; - var member = ResolveMember (type, memberName, instance == null); + var member = ResolveMember (type, memberName, instance == null, MemberTypes.Method); if (member == null || member.Length == 0) return false; return EvaluateMethod (str, member, instance, parameterValues, out val); @@ -694,22 +698,17 @@ namespace MonoDevelop.Projects.MSBuild val = null; // Find a method with a matching number of parameters - var method = FindBestOverload (member.OfType<MethodBase> (), parameterValues); + var (method, methodParams) = FindBestOverload (member, parameterValues, out var paramsArgType); if (method == null) return false; try { // Convert the given parameters to the types specified in the method signature - var methodParams = method.GetParameters (); - var convertedArgs = (methodParams.Length == parameterValues.Length) ? parameterValues : new object [methodParams.Length]; int numArgs = methodParams.Length; - Type paramsArgType = null; - if (methodParams.Length > 0 && methodParams [methodParams.Length - 1].ParameterType.IsArray && methodParams [methodParams.Length - 1].IsDefined (typeof (ParamArrayAttribute))) { - paramsArgType = methodParams [methodParams.Length - 1].ParameterType.GetElementType (); + if (paramsArgType != null) numArgs--; - } if (method.DeclaringType == typeof (IntrinsicFunctions) && method.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove) && parameterValues.Length == methodParams.Length - 1) { string startingDirectory = String.IsNullOrWhiteSpace (FullFileName) ? String.Empty : Path.GetDirectoryName (FullFileName); @@ -792,58 +791,158 @@ namespace MonoDevelop.Projects.MSBuild return false; } - MethodBase FindBestOverload (IEnumerable<MethodBase> methods, object [] args) + (MethodBase method, ParameterInfo[] parameters) FindBestOverload (IEnumerable<MemberInfo> members, object [] args, out Type paramsArgType) { - MethodBase methodWithParams = null; + (MethodBase, ParameterInfo[]) methodWithParams = default; + (MethodBase, ParameterInfo[]) validMatch = default; - foreach (var m in methods) { - var argInfo = m.GetParameters (); + paramsArgType = null; - // Exclude methods which take a complex object as argument - if (argInfo.Any (a => a.ParameterType != typeof(object) && Type.GetTypeCode (a.ParameterType) == TypeCode.Object && !IsParamsArg(a))) + foreach (var member in members) { + if (!(member is MethodBase m)) continue; - if (args.Length >= argInfo.Length - 1 && argInfo.Length > 0 && IsParamsArg (argInfo [argInfo.Length - 1])) { - methodWithParams = m; - continue; - } - if (args.Length != argInfo.Length) { - if (args.Length == argInfo.Length - 1 && m.DeclaringType != typeof (IntrinsicFunctions) || m.Name != nameof(IntrinsicFunctions.GetPathOfFileAbove)) { + var argInfo = m.GetParameters (); + + if (args.Length == argInfo.Length - 1) { + if (m.DeclaringType == typeof (IntrinsicFunctions) && m.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove)) { + validMatch = (m, argInfo); continue; } } - bool isValid = true; - for (int n = 0; n < args.Length; n++) { - if (!CanConvertArg (m, n, args [n], argInfo [n].ParameterType)) { - isValid = false; - break; - } + // Unable to match in this case. + if (args.Length < argInfo.Length - 1) + continue; + + var kind = MatchArgs (args, argInfo); + if (kind == MatchKind.Exact) + return (m, argInfo); + + if (kind == MatchKind.CanConvert) + validMatch = (m, argInfo); + else if (kind == MatchKind.Params) { + methodWithParams = (m, argInfo); + paramsArgType = argInfo [argInfo.Length - 1].ParameterType.GetElementType (); } - if (isValid) - return m; } - return methodWithParams; + + return validMatch != default ? validMatch : methodWithParams; } - bool IsParamsArg (ParameterInfo pi) + enum MatchKind + { + None, + Params, + CanConvert, + Exact, + } + + static MatchKind MatchArgs (object[] args, ParameterInfo[] parameters) + { + bool isParams = parameters.Length > 0 && IsParamsArg (parameters [parameters.Length - 1]); + + int last = parameters.Length; + if (isParams) + last--; + else if (args.Length != parameters.Length) + return MatchKind.None; + + var kind = MatchKind.Exact; + for (int n = 0; n < last; n++) { + var parameterType = parameters [n].ParameterType; + + var other = Match (parameterType, args [n]); + if (other == MatchKind.None) + return MatchKind.None; + + if (other == MatchKind.CanConvert) + kind = MatchKind.CanConvert; + } + + if (!isParams) + return kind; + + // Check implicit argument + if (args.Length == last) + return MatchKind.Params; + + var elementType = parameters[last].ParameterType.GetElementType (); + if (IsComplexType (elementType)) + return MatchKind.None; + + int argsRemaining = args.Length - last; + if (argsRemaining == 1 && elementType == typeof(char)) { + if (Match (parameters [last].ParameterType, args [last], checkComplexType: false) != MatchKind.None) + return MatchKind.Params; + } + + for (int n_arg = last; n_arg < args.Length; ++n_arg) { + if (Match (elementType, args [n_arg]) == MatchKind.None) + return MatchKind.None; + } + + return MatchKind.Params; + + static bool IsComplexType (Type type) + { + return Type.GetTypeCode (type) == TypeCode.Object && type != typeof (object); + } + + static MatchKind Match (Type parameterType, object argument, bool checkComplexType = true) + { + if (parameterType.IsInstanceOfType (argument)) + return MatchKind.Exact; + + if (checkComplexType && IsComplexType (parameterType)) + return MatchKind.None; + + if (CanConvertArg (argument, parameterType)) + return MatchKind.CanConvert; + + + return MatchKind.None; + } + } + + static bool IsParamsArg (ParameterInfo pi) { return pi.ParameterType.IsArray && pi.IsDefined (typeof (ParamArrayAttribute)); } - bool CanConvertArg (MethodBase method, int argNum, object value, Type parameterType) + static bool CanConvertArg (object value, Type parameterType) { var sval = value as string; if (sval == "null" || value == null) - return !parameterType.IsValueType || typeof(Nullable).IsInstanceOfType (parameterType); + return !parameterType.IsValueType || Nullable.GetUnderlyingType (parameterType) != null; if (sval != null && parameterType == typeof (char [])) return true; - if (parameterType == typeof (char) && sval != null && sval.Length != 1) + if (sval != null && sval.Length != 1 && parameterType == typeof (char)) { return false; + } - return true; + if (sval != null && parameterType.IsEnum) { + // Enum.Parse expects comma separated values. + var enumValue = sval.Replace ('|', ',') + .Replace (parameterType.FullName + ".", "") + .Replace (parameterType.Name + ".", ""); + + try { + _ = Enum.Parse (parameterType, enumValue, ignoreCase: true); + return true; + } catch { + return false; + } + } + + try { + _ = Convert.ChangeType (value, parameterType, CultureInfo.InvariantCulture); + return true; + } catch { + return false; + } } object ConvertArg (MethodBase method, int argNum, object value, Type parameterType) @@ -856,11 +955,11 @@ namespace MonoDevelop.Projects.MSBuild return sval.ToCharArray (); if (sval != null && parameterType.IsEnum) { - var enumValue = sval; - if (enumValue.StartsWith (parameterType.Name, StringComparison.Ordinal)) - enumValue = enumValue.Substring (parameterType.Name.Length + 1); - if (enumValue.StartsWith (parameterType.FullName, StringComparison.Ordinal)) - enumValue = enumValue.Substring (parameterType.FullName.Length + 1); + // Enum.Parse expects comma separated values. + var enumValue = sval.Replace ('|', ',') + .Replace (parameterType.FullName + ".", "") + .Replace (parameterType.Name + ".", ""); + return Enum.Parse(parameterType, enumValue, ignoreCase: true); } @@ -907,15 +1006,15 @@ namespace MonoDevelop.Projects.MSBuild { if (typeName == "MSBuild") return typeof (Microsoft.Build.Evaluation.IntrinsicFunctions); - else { - var t = supportedTypeMembers.FirstOrDefault (st => st.Item1.FullName == typeName); - if (t == null) - return null; - return t.Item1; + + foreach (var kvp in supportedTypeMembers) { + if (kvp.Key.FullName == typeName) + return kvp.Key; } + return null; } - MemberInfo[] ResolveMember (Type type, string memberName, bool isStatic) + MemberInfo[] ResolveMember (Type type, string memberName, bool isStatic, MemberTypes memberTypes) { if (type == typeof (string) && memberName == "new") memberName = "Copy"; @@ -923,52 +1022,68 @@ namespace MonoDevelop.Projects.MSBuild type = typeof (Array); var flags = isStatic ? BindingFlags.Static : BindingFlags.Instance; if (type != typeof (Microsoft.Build.Evaluation.IntrinsicFunctions)) { - var t = supportedTypeMembers.FirstOrDefault (st => st.Item1 == type); - if (t == null) + if (!supportedTypeMembers.TryGetValue (type, out var list)) return null; - if (t.Item2 != null && !t.Item2.Contains (memberName)) + + if (list != null && !list.Contains (memberName)) return null; } else flags |= BindingFlags.NonPublic; - - return type.GetMember (memberName, flags | BindingFlags.Public | BindingFlags.IgnoreCase); + + return type.GetMember (memberName, memberTypes, flags | BindingFlags.Public | BindingFlags.IgnoreCase); } - static Tuple<Type, string []> [] supportedTypeMembers = { - Tuple.Create (typeof(System.Array), (string[]) null), - Tuple.Create (typeof(System.Byte), (string[]) null), - Tuple.Create (typeof(System.Char), (string[]) null), - Tuple.Create (typeof(System.Convert), (string[]) null), - Tuple.Create (typeof(System.DateTime), (string[]) null), - Tuple.Create (typeof(System.Decimal), (string[]) null), - Tuple.Create (typeof(System.Double), (string[]) null), - Tuple.Create (typeof(System.Enum), (string[]) null), - Tuple.Create (typeof(System.Guid), (string[]) null), - Tuple.Create (typeof(System.Int16), (string[]) null), - Tuple.Create (typeof(System.Int32), (string[]) null), - Tuple.Create (typeof(System.Int64), (string[]) null), - Tuple.Create (typeof(System.IO.Path), (string[]) null), - Tuple.Create (typeof(System.Math), (string[]) null), - Tuple.Create (typeof(System.UInt16), (string[]) null), - Tuple.Create (typeof(System.UInt32), (string[]) null), - Tuple.Create (typeof(System.UInt64), (string[]) null), - Tuple.Create (typeof(System.SByte), (string[]) null), - Tuple.Create (typeof(System.Single), (string[]) null), - Tuple.Create (typeof(System.String), (string[]) null), - Tuple.Create (typeof(System.StringComparer), (string[]) null), - Tuple.Create (typeof(System.TimeSpan), (string[]) null), - Tuple.Create (typeof(System.Text.RegularExpressions.Regex), (string[]) null), - Tuple.Create (typeof(Microsoft.Build.Utilities.ToolLocationHelper), (string[]) null), - Tuple.Create (typeof(System.Globalization.CultureInfo), (string[]) null), - Tuple.Create (typeof(System.Environment), new string [] { - "CommandLine", "ExpandEnvironmentVariables", "GetEnvironmentVariable", "GetEnvironmentVariables", "GetFolderPath", "GetLogicalDrives" - }), - Tuple.Create (typeof(System.IO.Directory), new string [] { - "GetDirectories", "GetFiles", "GetLastAccessTime", "GetLastWriteTime", "GetParent" - }), - Tuple.Create (typeof(System.IO.File), new string [] { - "Exists", "GetCreationTime", "GetAttributes", "GetLastAccessTime", "GetLastWriteTime", "ReadAllText" - }), + sealed class TypeEqualityComparer : IEqualityComparer<Type> + { + public bool Equals (Type x, Type y) => x == y; + + public int GetHashCode (Type obj) => obj?.GetHashCode () ?? 0; + } + + static readonly Dictionary<Type, string []> supportedTypeMembers = new Dictionary<Type, string []> (new TypeEqualityComparer()) { + { typeof(System.Array), null }, + { typeof(System.Byte), null }, + { typeof(System.Char), null }, + { typeof(System.Convert), null }, + { typeof(System.DateTime), null }, + { typeof(System.Decimal), null }, + { typeof(System.Double), null }, + { typeof(System.Enum), null }, + { typeof(System.Guid), null }, + { typeof(System.Int16), null }, + { typeof(System.Int32), null }, + { typeof(System.Int64), null }, + { typeof(System.IO.Path), null }, + { typeof(System.Math), null }, + { typeof(System.UInt16), null }, + { typeof(System.UInt32), null }, + { typeof(System.UInt64), null }, + { typeof(System.SByte), null }, + { typeof(System.Single), null }, + { typeof(System.String), null }, + { typeof(System.StringComparer), null }, + { typeof(System.TimeSpan), null }, + { typeof(System.Text.RegularExpressions.Regex), null }, + { typeof(Microsoft.Build.Utilities.ToolLocationHelper), null }, + { typeof(System.Globalization.CultureInfo), null }, + { + typeof (System.Environment), + new string [] { + "CommandLine", "ExpandEnvironmentVariables", "GetEnvironmentVariable", "GetEnvironmentVariables", "GetFolderPath", "GetLogicalDrives" + } + }, + { + typeof (System.IO.Directory), + new string [] { + "GetDirectories", "GetFiles", "GetLastAccessTime", "GetLastWriteTime", "GetParent" + } + }, + { + typeof (System.IO.File), + new string [] { + "Exists", "GetCreationTime", "GetAttributes", "GetLastAccessTime", "GetLastWriteTime", "ReadAllText" + } + }, }; int FindNextTag (string str, int i) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs index e7c8945f90..fe0e089335 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs @@ -168,7 +168,7 @@ namespace MonoDevelop.Projects.MSBuild internal async Task WriteFile (FilePath file, object obj, ProgressMonitor monitor) { if (slnFileFormat.CanWriteFile (obj, this)) { - await slnFileFormat.WriteFile (file, obj, true, monitor); + await slnFileFormat.WriteFile (file, obj, true, monitor).ConfigureAwait (false); } else { throw new NotSupportedException (); } @@ -177,7 +177,7 @@ namespace MonoDevelop.Projects.MSBuild internal async Task<object> ReadFile (FilePath file, Type expectedType, MonoDevelop.Core.ProgressMonitor monitor) { if (slnFileFormat.CanReadFile (file, this)) - return await slnFileFormat.ReadFile (file, monitor); + return await slnFileFormat.ReadFile (file, monitor).ConfigureAwait(false); else throw new NotSupportedException (); }
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs index a23254c86c..4b21073b76 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs @@ -115,7 +115,7 @@ namespace MonoDevelop.Projects.MSBuild } catch (Exception ex) { // If the project can't be evaluated don't crash LoggingService.LogError ("MSBuild project could not be evaluated", ex); - throw new ProjectEvaluationException (msproject, ex.Message); + throw new ProjectEvaluationException (msproject, ex.Message, ex); } finally { if (oldProjectInstance != null) engine.DisposeProjectInstance (oldProjectInstance); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs index 703bbcf97d..398aa31187 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs @@ -784,26 +784,24 @@ namespace MonoDevelop.Projects.MSBuild return Task.FromResult<SolutionItem> (new GenericProject ()); // Unknown project types are already displayed in the solution view, we don't need to tell the user with a modal dialog as well - return Task<SolutionItem>.Factory.StartNew (delegate { - var t = ReadGenericProjectType (file); - if (t == null) - throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type")); + var t = ReadGenericProjectType (file); + if (t == null) + return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type"))); - var dt = Services.ProjectService.DataContext.GetConfigurationDataType (t); - if (dt != null) { - if (!typeof (Project).IsAssignableFrom (dt.ValueType)) - throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t)); + var dt = Services.ProjectService.DataContext.GetConfigurationDataType (t); + if (dt != null) { + if (!typeof (Project).IsAssignableFrom (dt.ValueType)) + return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t))); - return (SolutionItem)Activator.CreateInstance (dt.ValueType); - } + return Task.FromResult ((SolutionItem)Activator.CreateInstance (dt.ValueType)); + } - Type type; - lock (genericProjectTypes) { - if (!genericProjectTypes.TryGetValue (t, out type)) - throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t)); - } - return (SolutionItem)Activator.CreateInstance (type); - }); + Type type; + lock (genericProjectTypes) { + if (!genericProjectTypes.TryGetValue (t, out type)) + return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t))); + } + return Task.FromResult ((SolutionItem)Activator.CreateInstance (type)); } static string ReadGenericProjectType (string file) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs index 000fcea525..88775b3e5d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs @@ -29,12 +29,16 @@ namespace MonoDevelop.Projects.MSBuild { public class ProjectEvaluationException: ApplicationException { - public ProjectEvaluationException (MSBuildProject project, string message): base (message) + internal ProjectEvaluationException (MSBuildProject project, string message, Exception innerException) : base (message, innerException) { Project = project; } - public MSBuildProject Project { get; private set; } + public ProjectEvaluationException (MSBuildProject project, string message): this (project, message, null) + { + } + + public MSBuildProject Project { get; } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs index 742edb3d99..581fef41d4 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs @@ -64,22 +64,20 @@ namespace MonoDevelop.Projects.MSBuild return obj is Solution; } - public Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor) + public async Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor) { - return Task.Run (async delegate { - Solution sol = (Solution)obj; + Solution sol = (Solution)obj; - try { - monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1); - await WriteFileInternal (file, file, sol, saveProjects, monitor).ConfigureAwait (false); - } catch (Exception ex) { - monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex); - LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex); - throw; - } finally { - monitor.EndTask (); - } - }); + try { + monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1); + await WriteFileInternal (file, file, sol, saveProjects, monitor).ConfigureAwait (false); + } catch (Exception ex) { + monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex); + LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex); + throw; + } finally { + monitor.EndTask (); + } } async Task WriteFileInternal (string file, string sourceFile, Solution solution, bool saveProjects, ProgressMonitor monitor) @@ -91,7 +89,7 @@ namespace MonoDevelop.Projects.MSBuild try { monitor.BeginStep (); item.SavingSolution = true; - await item.SaveAsync (monitor); + await item.SaveAsync (monitor).ConfigureAwait (false); } finally { item.SavingSolution = false; } @@ -377,21 +375,19 @@ namespace MonoDevelop.Projects.MSBuild try { monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading solution: {0}"), fileName), 1); monitor.BeginStep (); - await sol.OnBeginLoad (); + await sol.OnBeginLoad ().ConfigureAwait (false); var projectLoadMonitor = monitor as ProjectLoadProgressMonitor; if (projectLoadMonitor != null) projectLoadMonitor.CurrentSolution = sol; - await Task.Run (() => { - sol.ReadSolution (monitor); - }); + sol.ReadSolution (monitor); } catch (Exception ex) { monitor.ReportError (GettextCatalog.GetString ("Could not load solution: {0}", fileName), ex); - await sol.OnEndLoad (); + await sol.OnEndLoad ().ConfigureAwait (false); sol.NotifyItemReady (); monitor.EndTask (); throw; } - await sol.OnEndLoad (); + await sol.OnEndLoad ().ConfigureAwait (false); sol.NotifyItemReady (); monitor.EndTask (); return sol; @@ -533,7 +529,7 @@ namespace MonoDevelop.Projects.MSBuild } } monitor.Step (1); - }); + }, TaskScheduler.Default); loadTasks.Add (ft); // Limit the number of concurrent tasks. Por solutions with many projects, spawning one thread per diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs index ffaaef930f..4bb348eddc 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs @@ -215,11 +215,9 @@ namespace MonoDevelop.Projects public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) { - return Task<SolutionItem>.Factory.StartNew (delegate { - CompiledAssemblyProject p = new CompiledAssemblyProject (); - p.LoadFrom (fileName); - return p; - }); + CompiledAssemblyProject p = new CompiledAssemblyProject (); + p.LoadFrom (fileName); + return Task.FromResult<SolutionItem> (p); } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs index f5b1f1922c..8172ed8212 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs @@ -41,26 +41,22 @@ namespace MonoDevelop.Projects return false; } - public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) + public override async Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) { - return Task.Run (() => { - foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) { - if (f.CanReadFile (fileName, typeof(SolutionItem))) - return MSBuildProjectService.LoadItem (monitor, fileName, f, typeGuid, itemGuid, ctx); - } - throw new NotSupportedException (); - }); + foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) { + if (f.CanReadFile (fileName, typeof(SolutionItem))) + return await MSBuildProjectService.LoadItem (monitor, fileName, f, typeGuid, itemGuid, ctx).ConfigureAwait (false); + } + throw new NotSupportedException (); } - public override Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName) + public override async Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName) { - return Task.Run (async () => { - foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) { - if (f.CanReadFile (fileName, typeof (WorkspaceItem))) - return (WorkspaceItem)await f.ReadFile (fileName, typeof (WorkspaceItem), monitor).ConfigureAwait (false); - } - throw new NotSupportedException (); - }); + foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) { + if (f.CanReadFile (fileName, typeof (WorkspaceItem))) + return (WorkspaceItem)await f.ReadFile (fileName, typeof (WorkspaceItem), monitor).ConfigureAwait (false); + } + throw new NotSupportedException (); } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index 3df66730cc..a8a7c72dd0 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -415,9 +415,7 @@ namespace MonoDevelop.Projects protected override Task OnLoad (ProgressMonitor monitor) { - return Task.Run (async delegate { - await LoadAsync (monitor); - }); + return LoadAsync (monitor); } async Task LoadAsync (ProgressMonitor monitor) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs index 7997a72146..4b57332e0d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs @@ -54,7 +54,7 @@ namespace MonoDevelop.Projects TargetFramework defaultTargetFramework; string defaultPlatformTarget = "anycpu"; - static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_7; + static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_7_2; public const string BuildTarget = "Build"; public const string CleanTarget = "Clean"; @@ -123,7 +123,7 @@ namespace MonoDevelop.Projects var r = GetObjectReaderForFile (file, typeof(SolutionItem)); if (r == null) throw new UnknownSolutionItemTypeException (); - SolutionItem loadedItem = await r.LoadSolutionItem (monitor, ctx, file, format, typeGuid, itemGuid); + SolutionItem loadedItem = await Task.Run (() => r.LoadSolutionItem (monitor, ctx, file, format, typeGuid, itemGuid)); if (loadedItem != null) { loadedItem.NeedsReload = false; UpdateReadSolutionItemMetadata (metadata, loadedItem); @@ -216,7 +216,7 @@ namespace MonoDevelop.Projects var r = GetObjectReaderForFile (file, typeof(WorkspaceItem)); if (r == null) throw new InvalidOperationException ("Invalid file format: " + file); - WorkspaceItem item = await r.LoadWorkspaceItem (monitor, fullpath); + WorkspaceItem item = await Task.Run (() => r.LoadWorkspaceItem (monitor, fullpath)); if (item != null) item.NeedsReload = false; else diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs index e7514fe8f1..195b692af1 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs @@ -38,6 +38,8 @@ namespace MonoDevelop.Projects [ExportProjectModelExtension] public class SdkProjectExtension : DotNetProjectExtension { + HashSet<(string Name, string Include)> evaluatedItems; + MSBuildSdkProject msbuildSdkProject = new MSBuildSdkProject (); string[] cachedBuildActions; @@ -53,8 +55,7 @@ namespace MonoDevelop.Projects /// </summary> internal static bool FileShouldBeHidden (FilePath file) { - return file.HasExtension (".userprefs") || - file.FileName == ".DS_Store"; + return file.HasExtension (".userprefs") || file.HasFileName (".DS_Store"); } public IEnumerable<string> TargetFrameworks { @@ -109,6 +110,7 @@ namespace MonoDevelop.Projects Project.UseFileWatcher = true; cachedBuildActions = null; + evaluatedItems = null; } internal protected override void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject) @@ -129,36 +131,15 @@ namespace MonoDevelop.Projects { var sourceFiles = await base.OnGetSourceFiles (monitor, configuration); - return AddMissingProjectFiles (sourceFiles, configuration); - } - - ImmutableArray<ProjectFile> AddMissingProjectFiles (ImmutableArray<ProjectFile> files, ConfigurationSelector configuration) - { - ImmutableArray<ProjectFile>.Builder missingFiles = null; - foreach (ProjectFile existingFile in Project.Files.Where (file => file.BuildAction == BuildAction.Compile)) { - if (!files.Any (file => file.FilePath == existingFile.FilePath)) { - if (missingFiles == null) - missingFiles = ImmutableArray.CreateBuilder<ProjectFile> (); - missingFiles.Add (existingFile); - } - } - // Ensure generated assembly info file is available to type system. It is created in the obj // directory and is excluded from the project with a wildcard exclude but the type system needs it to // ensure the project's assembly information is correct to prevent diagnostic errors. var generatedAssemblyInfoFile = GetGeneratedAssemblyInfoFile (configuration); if (generatedAssemblyInfoFile != null) { - if (missingFiles == null) - missingFiles = ImmutableArray.CreateBuilder<ProjectFile> (); - missingFiles.Add (generatedAssemblyInfoFile); + return sourceFiles.Add (generatedAssemblyInfoFile); } - if (missingFiles == null) - return files; - - missingFiles.Capacity = missingFiles.Count + files.Length; - missingFiles.AddRange (files); - return missingFiles.MoveToImmutable (); + return sourceFiles; } ProjectFile GetGeneratedAssemblyInfoFile (ConfigurationSelector configuration) @@ -185,14 +166,23 @@ namespace MonoDevelop.Projects // project file is being saved. } - bool IsFSharpSdkProject () + bool? isFSharpSdkProject; + bool IsLegacyFSharpSdkProject () { - var sdks = Project.MSBuildProject.GetReferencedSDKs (); - for (var i = 0; i < sdks.Length; i++) { - if (sdks [i].Contains ("FSharp")) - return true; + if (isFSharpSdkProject is null) { + isFSharpSdkProject = ContainsFSharpSdk (Project.MSBuildProject.GetReferencedSDKs ()); + } + + return isFSharpSdkProject.Value; + + static bool ContainsFSharpSdk (string[] sdks) + { + for (var i = 0; i < sdks.Length; i++) { + if (sdks [i].Contains ("FSharp")) + return true; + } + return false; } - return false; } internal protected override bool OnGetSupportsImportedItem (IMSBuildItemEvaluated buildItem) @@ -200,7 +190,7 @@ namespace MonoDevelop.Projects if (!IsBuildActionSupported (buildItem.Name)) return false; - if (IsFSharpSdkProject ()) { + if (IsLegacyFSharpSdkProject ()) { // Ignore imported F# files. F# files are defined in the main project. // This prevents duplicate F# files when a new project is first created. if (buildItem.Include.EndsWith (".fs", StringComparison.OrdinalIgnoreCase)) @@ -210,11 +200,15 @@ namespace MonoDevelop.Projects if (IsFromSharedProject (buildItem)) return false; - // HACK: Remove any imported items that are not in the EvaluatedItems - // This may happen if a condition excludes the item. All items passed to the - // OnGetSupportsImportedItem are from the EvaluatedItemsIgnoringCondition - return Project.MSBuildProject.EvaluatedItems - .Any (item => item.IsImported && item.Name == buildItem.Name && item.Include == buildItem.Include); + evaluatedItems ??= CreateEvaluatedItemsCache (Project.MSBuildProject); + return evaluatedItems.Contains ((buildItem.Name, buildItem.Include)); + + static HashSet<(string, string)> CreateEvaluatedItemsCache (MSBuildProject project) + => new HashSet<(string Name, string Include)> ( + project.EvaluatedItems + .Where (x => x.IsImported) + .Select (x => (x.Name, x.Include)) + ); } /// <summary> @@ -262,6 +256,8 @@ namespace MonoDevelop.Projects internal protected override async Task OnReevaluateProject (ProgressMonitor monitor) { await base.OnReevaluateProject (monitor); + + isFSharpSdkProject = null; UpdateHiddenFiles (Project.Files); } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs index 6765edf762..2d42a1576f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs @@ -96,15 +96,13 @@ namespace MonoDevelop.Projects return null; } - public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) + public override async Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) { - return Task.Run (() => { - if (CanRead (fileName, typeof (SolutionItem))) { - return MSBuildProjectService.LoadItem (monitor, fileName, MSBuildFileFormat.VS2012, typeGuid, itemGuid, ctx); - } + if (CanRead (fileName, typeof (SolutionItem))) { + return await MSBuildProjectService.LoadItem (monitor, fileName, MSBuildFileFormat.VS2012, typeGuid, itemGuid, ctx); + } - throw new NotSupportedException (); - }); + throw new NotSupportedException (); } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs index 8dce5f1327..2a9c0c96e3 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs @@ -460,7 +460,7 @@ namespace MonoDevelop.Projects if (ItemExtension.OnCheckHasSolutionData () && !SavingSolution && ParentSolution != null) { // The project has data that has to be saved in the solution, but the solution is not being saved. Do it now. - await SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor); + await Task.Run (() => SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor)); ParentSolution.NeedsReload = false; } } @@ -1232,12 +1232,12 @@ namespace MonoDevelop.Projects protected virtual Task OnLoad (ProgressMonitor monitor) { - return Task.FromResult (0); + return Task.CompletedTask; } protected internal virtual Task OnSave (ProgressMonitor monitor) { - return Task.FromResult (0); + return Task.CompletedTask; } public FilePath GetAbsoluteChildPath (FilePath relPath) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs index 639c96b249..7b4dec5b75 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs @@ -276,7 +276,7 @@ namespace MonoDevelop.Projects FileService.RequestFileEdit (f); try { fileStatusTracker.BeginSave (); - await ItemExtension.Save (monitor); + await Task.Run (() => ItemExtension.Save (monitor)); await OnSaveUserProperties (); // Call the virtual to avoid the lock OnSaved (new WorkspaceItemEventArgs (this)); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs index 9c0a453544..b205558a76 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs @@ -41,12 +41,12 @@ namespace MonoDevelop.Projects public virtual Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid) { - throw new NotSupportedException (); + return Task.FromException<SolutionItem> (new NotSupportedException ()); } public virtual Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName) { - throw new NotSupportedException (); + return Task.FromException<WorkspaceItem> (new NotSupportedException ()); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs index f96243af37..7e4c748ab5 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs @@ -45,13 +45,11 @@ namespace MonoDevelop.Projects return false; } - public override Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName) + public override async Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName) { - return Task.Run (async () => { - var workspaceItem = ReadWorkspaceItemFile (fileName, monitor); - await workspaceItem.LoadUserProperties ().ConfigureAwait (false); - return workspaceItem; - }); + var workspaceItem = ReadWorkspaceItemFile (fileName, monitor); + await workspaceItem.LoadUserProperties ().ConfigureAwait (false); + return workspaceItem; } WorkspaceItem ReadWorkspaceItemFile (FilePath fileName, ProgressMonitor monitor) |