internal static void VerifyThrowInternalLength(string parameterValue, string parameterName) { ErrorUtilities.VerifyThrowInternalNull((object)parameterValue, parameterName); if (parameterValue.Length != 0) { return; } ErrorUtilities.ThrowInternalError("{0} unexpectedly empty", (object)parameterName); }
/// <summary> /// Throws an InvalidProjectFileException using the given data. /// /// PERF WARNING: calling a method that takes a variable number of arguments /// is expensive, because memory is allocated for the array of arguments -- do /// not call this method repeatedly in performance-critical scenarios /// /// </summary> /// <param name="errorSubCategoryResourceName">The resource string for the /// error sub-category (can be null).</param> /// <param name="elementLocation">The <see cref="IElementLocation"/> of the element.</param> /// <param name="resourceName">The resource string for the error message.</param> /// <param name="args">Extra arguments for formatting the error message.</param> private static void ThrowInvalidProject ( string errorSubCategoryResourceName, IElementLocation elementLocation, string resourceName, params object[] args ) { ErrorUtilities.VerifyThrowInternalNull(elementLocation, "elementLocation"); #if DEBUG if (errorSubCategoryResourceName != null) { ResourceUtilities.VerifyResourceStringExists(errorSubCategoryResourceName); } ResourceUtilities.VerifyResourceStringExists(resourceName); #endif string errorSubCategory = null; if (errorSubCategoryResourceName != null) { errorSubCategory = AssemblyResources.GetString(errorSubCategoryResourceName); } string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, resourceName, args); Exception exceptionToThrow = new InvalidProjectFileException(elementLocation.File, elementLocation.Line, elementLocation.Column, 0 /* Unknown end line */, 0 /* Unknown end column */, message, errorSubCategory, errorCode, helpKeyword); #if FEATURE_MSBUILD_DEBUGGER if (!DebuggerManager.DebuggingEnabled) { throw exceptionToThrow; } try { throw exceptionToThrow; } catch (InvalidProjectFileException ex) { // To help out the user debugging their project, break into the debugger here. // That's because otherwise, since they're debugging our optimized code with JMC on, // they may not be able to break on this exception at all themselves. // Also, dump the exception information, as it's hard to see in optimized code. // Note that we use Trace as Debug.WriteLine is not compiled in release builds, which is // what we are in here. Trace.WriteLine(ex.ToString()); Debugger.Break(); throw; } #else throw exceptionToThrow; #endif }
private static Assembly GetEntryAssembly() { #if FEATURE_ASSEMBLY_GETENTRYASSEMBLY return(System.Reflection.Assembly.GetEntryAssembly()); #else var getEntryAssembly = typeof(Assembly).GetMethod("GetEntryAssembly"); ErrorUtilities.VerifyThrowInternalNull(getEntryAssembly, "Assembly does not have the method GetEntryAssembly"); return((Assembly)getEntryAssembly.Invoke(null, Array.Empty <object>())); #endif }
private static CultureInfo[] GetValidCultures() { var cultureTypesType = s_cultureInfoGetCultureMethod?.GetParameters().FirstOrDefault()?.ParameterType; ErrorUtilities.VerifyThrow(cultureTypesType?.Name == "CultureTypes" && Enum.IsDefined(cultureTypesType, "AllCultures"), "GetCulture is expected to accept CultureTypes.AllCultures"); var allCulturesEnumValue = Enum.Parse(cultureTypesType, "AllCultures", true); var cultures = s_cultureInfoGetCultureMethod.Invoke(null, new[] { allCulturesEnumValue }) as CultureInfo[]; ErrorUtilities.VerifyThrowInternalNull(cultures, "CultureInfo.GetCultures should work if all reflection checks pass"); return(cultures); }
private static void ThrowInvalidProject ( string errorSubCategoryResourceName, IElementLocation elementLocation, string resourceName, params object[] args ) { ErrorUtilities.VerifyThrowInternalNull(elementLocation, nameof(elementLocation)); #if DEBUG if (errorSubCategoryResourceName != null) { ResourceUtilities.VerifyResourceStringExists(errorSubCategoryResourceName); } ResourceUtilities.VerifyResourceStringExists(resourceName); #endif string errorSubCategory = errorSubCategoryResourceName is null ? null : AssemblyResources.GetString(errorSubCategoryResourceName); string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(out string errorCode, out string helpKeyword, resourceName, args); throw new InvalidProjectFileException(elementLocation.File, elementLocation.Line, elementLocation.Column, 0 /* Unknown end line */, 0 /* Unknown end column */, message, errorSubCategory, errorCode, helpKeyword); }
/// <summary> /// Add or rename an entry in the cache. /// Old full path may be null iff it was not already in the cache. /// </summary> /// <remarks> /// Must be called within the cache lock. /// </remarks> private void RenameEntryInternal(string oldFullPathIfAny, ProjectRootElement projectRootElement) { ErrorUtilities.VerifyThrowInternalNull(projectRootElement.FullPath, "FullPath"); if (oldFullPathIfAny != null) { ErrorUtilities.VerifyThrowInternalRooted(oldFullPathIfAny); ErrorUtilities.VerifyThrow(_weakCache[oldFullPathIfAny] == projectRootElement, "Should already be present"); _weakCache.Remove(oldFullPathIfAny); } // There may already be a ProjectRootElement in the cache with the new name. In this case we cannot throw an exception; // we must merely replace it. This is because it may be an unrooted entry // (and thus gone from the client's point of view) that merely remains // in the cache because we still have a reference to it from our strong cache. // Another possibility is that there are two, unrelated, un-saved, in-memory projects that were given the same path. // Replacing the cache entry does not in itself cause a problem -- if there are any actual users of the old // entry they will not be affected. There would then exist more than one ProjectRootElement with the same path, // but clients ought not get themselves into such a state - and unless they save them to disk, // it may not be a problem. Replacing also doesn't cause a problem for the strong cache, // as it is never consulted by us, but it is reasonable for us to remove the old entry in that case. ProjectRootElement existingWeakEntry; _weakCache.TryGetValue(projectRootElement.FullPath, out existingWeakEntry); if (existingWeakEntry != null && !Object.ReferenceEquals(existingWeakEntry, projectRootElement)) { _strongCache.Remove(existingWeakEntry); RaiseProjectRootElementRemovedFromStrongCache(existingWeakEntry); } DebugTraceCache("Adding: ", projectRootElement.FullPath); _weakCache[projectRootElement.FullPath] = projectRootElement; BoostEntryInStrongCache(projectRootElement); }
/// <summary> /// Returns an existing ProjectRootElement for the specified file path, if any. /// If none exists, calls the provided delegate to load one, and adds that to the cache. /// The reason that it calls back to do this is so that the cache is locked between determining /// that the entry does not exist and adding the entry. /// /// If <see cref="_autoReloadFromDisk"/> was set to true, and the file on disk has changed since it was cached, /// it will be reloaded before being returned. /// /// Thread safe. /// </summary> /// <remarks> /// Never needs to consult the strong cache as well, since if the item is in there, it will /// not have left the weak cache. /// If item is found, boosts it to the top of the strong cache. /// </remarks> /// <param name="projectFile">The project file which contains the ProjectRootElement. Must be a full path.</param> /// <param name="openProjectRootElement">The delegate to use to load if necessary. May be null.</param> /// <param name="isExplicitlyLoaded"><code>true</code> if the project is explicitly loaded, otherwise <code>false</code>.</param> /// <param name="preserveFormatting"><code>true</code> to the project was loaded with the formated preserved, otherwise <code>false</code>.</param> /// <returns>The ProjectRootElement instance if one exists. Null otherwise.</returns> internal ProjectRootElement Get(string projectFile, OpenProjectRootElement openProjectRootElement, bool isExplicitlyLoaded, bool?preserveFormatting) { // Should already have been canonicalized ErrorUtilities.VerifyThrowInternalRooted(projectFile); lock (_locker) { ProjectRootElement projectRootElement; _weakCache.TryGetValue(projectFile, out projectRootElement); if (preserveFormatting != null && projectRootElement != null && projectRootElement.XmlDocument.PreserveWhitespace != preserveFormatting) { // Cached project doesn't match preserveFormatting setting, so reload it projectRootElement.Reload(true, preserveFormatting); } if (projectRootElement != null && _autoReloadFromDisk) { var fileInfo = FileUtilities.GetFileInfoNoThrow(projectFile); // If the file doesn't exist on disk, go ahead and use the cached version. // It's an in-memory project that hasn't been saved yet. if (fileInfo != null) { bool forgetEntry = false; if (fileInfo.LastWriteTime != projectRootElement.LastWriteTimeWhenRead) { // File was changed on disk by external means. Cached version is no longer reliable. // We could throw here or ignore the problem, but it is a common and reasonable pattern to change a file // externally and load a new project over it to see the new content. So we dump it from the cache // to force a load from disk. There might then exist more than one ProjectRootElement with the same path, // but clients ought not get themselves into such a state - and unless they save them to disk, // it may not be a problem. forgetEntry = true; } else if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDCACHECHECKFILECONTENT"))) { // QA tests run too fast for the timestamp check to work. This environment variable is for their // use: it checks the file content as well as the timestamp. That's better than completely disabling // the cache as we get test coverage of the rest of the cache code. XmlDocument document = new XmlDocument(); document.PreserveWhitespace = projectRootElement.XmlDocument.PreserveWhitespace; using (var xtr = XmlReaderExtension.Create(projectRootElement.FullPath, projectRootElement.ProjectRootElementCache.LoadProjectsReadOnly)) { document.Load(xtr.Reader); } string diskContent = document.OuterXml; string cacheContent = projectRootElement.XmlDocument.OuterXml; if (diskContent != cacheContent) { forgetEntry = true; } } if (forgetEntry) { ForgetEntry(projectRootElement); DebugTraceCache("Out of date dropped from XML cache: ", projectFile); projectRootElement = null; } } } if (projectRootElement == null && openProjectRootElement != null) { projectRootElement = openProjectRootElement(projectFile, this); ErrorUtilities.VerifyThrowInternalNull(projectRootElement, "projectRootElement"); ErrorUtilities.VerifyThrow(projectRootElement.FullPath == projectFile, "Got project back with incorrect path"); ErrorUtilities.VerifyThrow(_weakCache.Contains(projectFile), "Open should have renamed into cache and boosted"); } else if (projectRootElement != null) { DebugTraceCache("Satisfied from XML cache: ", projectFile); BoostEntryInStrongCache(projectRootElement); } // An implicit load will never reset the explicit flag. if (projectRootElement != null && isExplicitlyLoaded) { projectRootElement.MarkAsExplicitlyLoaded(); } return(projectRootElement); } }
internal static string ExtractMessageCode(bool msbuildCodeOnly, string message, out string code) { ErrorUtilities.VerifyThrowInternalNull(message, "message"); code = null; int startIndex = 0; while ((startIndex < message.Length) && char.IsWhiteSpace(message[startIndex])) { startIndex++; } if (msbuildCodeOnly) { if (((((message.Length < (startIndex + 8)) || (message[startIndex] != 'M')) || ((message[startIndex + 1] != 'S') || (message[startIndex + 2] != 'B'))) || (((message[startIndex + 3] < '0') || (message[startIndex + 3] > '9')) || ((message[startIndex + 4] < '0') || (message[startIndex + 4] > '9')))) || (((message[startIndex + 5] < '0') || (message[startIndex + 5] > '9')) || (((message[startIndex + 6] < '0') || (message[startIndex + 6] > '9')) || (message[startIndex + 7] != ':')))) { return(message); } code = message.Substring(startIndex, 7); startIndex += 8; } else { int num2 = startIndex; while (num2 < message.Length) { char ch = message[num2]; if (((ch < 'a') || (ch > 'z')) && ((ch < 'A') || (ch > 'Z'))) { break; } num2++; } if (num2 == startIndex) { return(message); } int num3 = num2; while (num3 < message.Length) { char ch2 = message[num3]; if ((ch2 < '0') || (ch2 > '9')) { break; } num3++; } if (num3 == num2) { return(message); } if ((num3 == message.Length) || (message[num3] != ':')) { return(message); } code = message.Substring(startIndex, num3 - startIndex); startIndex = num3 + 1; } while ((startIndex < message.Length) && char.IsWhiteSpace(message[startIndex])) { startIndex++; } if (startIndex < message.Length) { message = message.Substring(startIndex, message.Length - startIndex); } return(message); }
internal override ProjectRootElement Get(string projectFile, OpenProjectRootElement loadProjectRootElement, bool isExplicitlyLoaded, bool?preserveFormatting) { #if DEBUG // Verify that loadProjectRootElement delegate does not call ProjectRootElementCache.Get(). s_getEntriesNumber++; ErrorUtilities.VerifyThrow( s_getEntriesNumber == 1, "Reentrance to the ProjectRootElementCache.Get function detected." ); try { #endif // Should already have been canonicalized ErrorUtilities.VerifyThrowInternalRooted(projectFile); ProjectRootElement projectRootElement; lock (_locker) { _weakCache.TryGetValue(projectFile, out projectRootElement); if (projectRootElement != null) { BoostEntryInStrongCache(projectRootElement); // An implicit load will never reset the explicit flag. if (isExplicitlyLoaded) { projectRootElement.MarkAsExplicitlyLoaded(); } } else { DebugTraceCache("Not found in cache: ", projectFile); } if (preserveFormatting != null && projectRootElement != null && projectRootElement.XmlDocument.PreserveWhitespace != preserveFormatting) { // Cached project doesn't match preserveFormatting setting, so reload it projectRootElement.Reload(true, preserveFormatting); } } bool projectRootElementIsInvalid = IsInvalidEntry(projectFile, projectRootElement); if (projectRootElementIsInvalid) { DebugTraceCache("Not satisfied from cache: ", projectFile); ForgetEntryIfExists(projectRootElement); } if (loadProjectRootElement == null) { if (projectRootElement == null || projectRootElementIsInvalid) { return(null); } else { DebugTraceCache("Satisfied from XML cache: ", projectFile); return(projectRootElement); } } // Use openProjectRootElement to reload the element if the cache element does not exist or need to be reloaded. if (projectRootElement == null || projectRootElementIsInvalid) { // We do not lock loading with common _locker of the cache, to avoid lock contention. // Decided also not to lock this section with the key specific locker to avoid the overhead and code overcomplication, as // it is not likely that two threads would use Get function for the same project simultaneously and it is not a big deal if in some cases we load the same project twice. projectRootElement = loadProjectRootElement(projectFile, this); ErrorUtilities.VerifyThrowInternalNull(projectRootElement, "projectRootElement"); ErrorUtilities.VerifyThrow( projectRootElement.FullPath.Equals(projectFile, StringComparison.OrdinalIgnoreCase), "Got project back with incorrect path. Expected path: {0}, received path: {1}.", projectFile, projectRootElement.FullPath ); // An implicit load will never reset the explicit flag. if (isExplicitlyLoaded) { projectRootElement.MarkAsExplicitlyLoaded(); } // Update cache element. // It is unlikely, but it might be that while without the lock, the projectRootElement in cache was updated by another thread. // And here its entry will be replaced with the loaded projectRootElement. This is fine: // if loaded projectRootElement is out of date (so, it changed since the time we loaded it), it will be updated the next time some thread calls Get function. AddEntry(projectRootElement); } else { DebugTraceCache("Satisfied from XML cache: ", projectFile); } return(projectRootElement); #if DEBUG } finally { s_getEntriesNumber--; } #endif }
internal static string ExtractMessageCode(bool msbuildCodeOnly, string message, out string code) { ErrorUtilities.VerifyThrowInternalNull((object)message, "message"); code = (string)null; int startIndex1 = 0; while (startIndex1 < message.Length && char.IsWhiteSpace(message[startIndex1])) { ++startIndex1; } int startIndex2; if (msbuildCodeOnly) { if (message.Length < startIndex1 + 8 || (int)message[startIndex1] != 77 || ((int)message[startIndex1 + 1] != 83 || (int)message[startIndex1 + 2] != 66) || ((int)message[startIndex1 + 3] < 48 || (int)message[startIndex1 + 3] > 57 || ((int)message[startIndex1 + 4] < 48 || (int)message[startIndex1 + 4] > 57)) || ((int)message[startIndex1 + 5] < 48 || (int)message[startIndex1 + 5] > 57 || ((int)message[startIndex1 + 6] < 48 || (int)message[startIndex1 + 6] > 57) || (int)message[startIndex1 + 7] != 58)) { return(message); } code = message.Substring(startIndex1, 7); startIndex2 = startIndex1 + 8; } else { int index1; for (index1 = startIndex1; index1 < message.Length; ++index1) { char ch = message[index1]; if (((int)ch < 97 || (int)ch > 122) && ((int)ch < 65 || (int)ch > 90)) { break; } } if (index1 == startIndex1) { return(message); } int index2; for (index2 = index1; index2 < message.Length; ++index2) { char ch = message[index2]; if ((int)ch < 48 || (int)ch > 57) { break; } } if (index2 == index1 || index2 == message.Length || (int)message[index2] != 58) { return(message); } code = message.Substring(startIndex1, index2 - startIndex1); startIndex2 = index2 + 1; } while (startIndex2 < message.Length && char.IsWhiteSpace(message[startIndex2])) { ++startIndex2; } if (startIndex2 < message.Length) { message = message.Substring(startIndex2, message.Length - startIndex2); } return(message); }