Пример #1
0
 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);
 }
Пример #2
0
        /// <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
        }
Пример #3
0
        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
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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);
            }
        }
Пример #8
0
        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);
        }
Пример #9
0
        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
        }
Пример #10
0
        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);
        }