public void Test(string fileName)
        {
            RunTest(fileName, patternManager =>
            {
                ICSharpFile cSharpFile = GetCodeFile(Project, fileName);
                var testData           = GetTestData(cSharpFile);

                var patterns = patternManager.GetRegistrationsForFile(cSharpFile.GetSourceFile()).ToList();

                Assert.AreEqual(testData.Item1, patterns.Count,
                                "Mismatched number of expected registrations. Make sure the '// Patterns:' comment is correct");

                if (testData.Item1 > 0)
                {
                    // todo refactor this. This should be a set operation.

                    // checks matching files
                    foreach (ICSharpFile codeFile in testData.Item2.SelectNotNull(f => GetCodeFile(Project, f)))
                    {
                        codeFile.ProcessChildren <ITypeDeclaration>(declaration =>
                                                                    Assert.That(patterns.Any(r => r.Registration.IsSatisfiedBy(declaration.DeclaredElement)),
                                                                                "Of {0} registrations, at least one should match '{1}'", patterns.Count, declaration.CLRName));
                    }

                    // checks non-matching files
                    foreach (ICSharpFile codeFile in testData.Item3.SelectNotNull(f => GetCodeFile(Project, f)))
                    {
                        codeFile.ProcessChildren <ITypeDeclaration>(declaration =>
                                                                    Assert.That(patterns.All(r => !r.Registration.IsSatisfiedBy(declaration.DeclaredElement)),
                                                                                "Of {0} registrations, none should match '{1}'", patterns.Count, declaration.CLRName));
                    }
                }
            });
        }
示例#2
0
        protected override IDaemonStageProcess CreateProcess(IDaemonProcess process,
                                                             IContextBoundSettingsStore settings,
                                                             DaemonProcessKind processKind, ICSharpFile file)
        {
            var sourceFile = file.GetSourceFile();

            if (!file.GetProject().IsUnityProject() || !mySwaExtensionProvider.IsApplicable(sourceFile))
            {
                return(null);
            }

            return(new CallGraphProcess(process, processKind, file, myLogger, myContextProviders, myProblemAnalyzers));
        }
示例#3
0
        /// <summary>
        /// The execute transaction inner.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        /// <param name="textControl">
        /// The text control.
        /// </param>
        public override void ExecuteTransactionInner(ISolution solution, ITextControl textControl)
        {
            ICSharpFile file = Utils.GetCSharpFile(solution, textControl);

            Lifetimes.Using(
                lifetime =>
            {
                StyleCopApi api = solution.GetComponent <StyleCopApiPool>().GetInstance(lifetime);

                Settings settings = api.Settings.GetSettings(file.GetSourceFile().ToProjectFile());

                // Fixes SA1208, SA1209, SA1210, SA1211
                OrderingRules.ExecuteAll(file, settings);
            });
        }
        private void AnalyzeFile(ICSharpFile file, IHighlightingConsumer consumer)
        {
            if (!file.GetProject().IsUnityProject())
            {
                return;
            }

            var sourceFile = file.GetSourceFile();

            if (sourceFile == null)
            {
                return;
            }

            file.ProcessThisAndDescendants(this, consumer);
        }
示例#5
0
        /// <inheritdoc />
        public override void ExecuteTransactionInner(ISolution solution, ITextControl textControl)
        {
            ICSharpFile file = Utils.GetCSharpFile(solution, textControl);

            Lifetime.Using(
                lifetime =>
            {
                StyleCopApi api = solution.GetComponent <StyleCopApiPool>().GetInstance(lifetime);

                var settings = api.Settings.GetSettings(file.GetSourceFile().ToProjectFile());

                // this covers the issue that constants (and maybe others) return the class if called as GetContainingElement<IDeclaration>)
                IDeclaration declaration = Utils.GetTypeClosestToTextControl <IDeclaration>(solution, textControl);

                if (declaration != null)
                {
                    DocumentationRules.CheckDeclarationDocumentation(file, declaration, settings);
                }
            });
        }
示例#6
0
        private void AnalyzeFile(ICSharpFile file, IHighlightingConsumer consumer)
        {
            if (!file.GetProject().IsUnityProject())
            {
                return;
            }

            var sourceFile = file.GetSourceFile();

            if (sourceFile == null)
            {
                return;
            }

            // find hot methods in derived from MonoBehaviour classes.
            var hotRootMethods = FindHotRootMethods(file, sourceFile);

            if (hotRootMethods.Count == 0)
            {
                return;
            }
            myCheckForInterrupt();

            var context = GetHotMethodAnalyzerContext(consumer, hotRootMethods, sourceFile);

            myCheckForInterrupt();

            // Second step of propagation 'costly reachable mark'. Handles cycles in call graph
            PropagateCostlyReachableMark(context);
            myCheckForInterrupt();

            // highlight hot methods
            foreach (var hotMethodDeclaration in context.HotMethods)
            {
                HighlightHotMethod(hotMethodDeclaration, consumer);
            }

            // highlight all invocation which indirectly calls costly methods.
            // it is fast, because we have already calculated all data
            HighlightCostlyReachableInvocation(consumer, context);
        }
        private void AnalyzeFile(ICSharpFile file, IHighlightingConsumer consumer)
        {
            if (myProcessKind != DaemonProcessKind.VISIBLE_DOCUMENT && myProcessKind != DaemonProcessKind.SOLUTION_ANALYSIS)
            {
                return;
            }

            if (!file.GetProject().IsUnityProject())
            {
                return;
            }

            var sourceFile = file.GetSourceFile();

            if (sourceFile == null)
            {
                return;
            }

            // find hot methods in derived from MonoBehaviour classes.
            var hotRootMethods = FindHotRootMethods(file, sourceFile);

            if (hotRootMethods.Count == 0)
            {
                return;
            }
            ourCheckForInterrupt();

            var context = GetHotMethodAnalyzerContext(consumer, hotRootMethods, sourceFile);

            ourCheckForInterrupt();

            // Second step of propagation 'costly reachable mark'. Handles cycles in call graph
            PropagateCostlyReachableMark(context);
            ourCheckForInterrupt();

            // highlight all invocation which indirectly calls costly methods.
            // it is fast, because we have already calculated all data
            HighlightCostlyReachableInvocation(consumer, context);
        }
        private static void SortImports(ICSharpFile psiFile)
        {
            IUsingDirective[] imports = psiFile.Imports.ToArray();

            string   defaultNamespaceFirstPart = null;
            IProject project = psiFile.GetSourceFile().ToProjectFile()?.GetProject();

            if (project?.ProjectProperties is CSharpProjectProperties projectProperties)
            {
                defaultNamespaceFirstPart = projectProperties.CSharpBuildSettings.DefaultNamespace.SubstringBefore(".");
            }

            imports.Sort((x, y) => CompareUsingDirectives(x, y, defaultNamespaceFirstPart));

            foreach (IUsingDirective import in imports)
            {
                psiFile.RemoveImport(import);
            }

            foreach (IUsingDirective import in imports)
            {
                psiFile.AddImport(import);
            }
        }
        /// <summary>
        /// Inserts the file name into the file.
        /// </summary>
        /// <param name="file">
        /// The file to insert into.
        /// </param>
        public void InsertFileName(ICSharpFile file)
        {
            string fileName = file.GetSourceFile().ToProjectFile().Location.Name;

            FileHeader fileHeader = new FileHeader(file) { FileName = fileName };
            fileHeader.Update();
        }
        /// <summary>
        /// Updates the existing header or inserts one if missing.
        /// </summary>
        /// <param name="file">
        /// THe file to check the header on.
        /// </param>
        public void InsertFileHeader(ICSharpFile file)
        {
            FileHeader fileHeader = new FileHeader(file);
            DocumentationRulesConfiguration docConfig = this.GetDocumentationRulesConfig(file);

            fileHeader.FileName = file.GetSourceFile().ToProjectFile().Location.Name;
            fileHeader.CompanyName = docConfig.CompanyName;
            fileHeader.CopyrightText = docConfig.Copyright;
            fileHeader.Summary = Utils.GetSummaryText(file);

            fileHeader.Update();
        }
 /// <summary>
 /// Returns a config object exposing the current config settings for this file.
 /// </summary>
 /// <param name="file">
 /// The file to get the config for.
 /// </param>
 /// <returns>
 /// The configuration for the given file.
 /// </returns>
 public DocumentationRulesConfiguration GetDocumentationRulesConfig(ICSharpFile file)
 {
     return new DocumentationRulesConfiguration(file.GetSourceFile());
 }
        /// <summary>
        /// Inserts any missing items from the file header.
        /// Also formats the existing header ensuring that the top and bottom line start with 2 slashes and a space and that a newline follows the header.
        /// </summary>
        /// <param name="options">
        /// The options.
        /// </param>
        /// <param name="file">
        /// The file to update.
        /// </param>
        private void UpdateFileHeader(DocumentationOptions options, ICSharpFile file)
        {
            // The idea here is to load the existing header into our FileHeader object
            // The FileHeader object will ensure that the format of the header is correct even if we're not changing its contents
            // Thus we'll swap it out if its changed at the end.
            string fileName = file.GetSourceFile().ToProjectFile().Location.Name;
            UpdateFileHeaderStyle updateFileHeaderOption = options.SA1633SA1641UpdateFileHeader;

            if (updateFileHeaderOption == UpdateFileHeaderStyle.Ignore)
            {
                return;
            }

            DocumentationRulesConfiguration docConfig = this.GetDocumentationRulesConfig(file);
            string summaryText = Utils.GetSummaryText(file);
            FileHeader fileHeader = new FileHeader(file) { InsertSummary = options.SA1639FileHeaderMustHaveSummary };

            switch (updateFileHeaderOption)
            {
                case UpdateFileHeaderStyle.ReplaceCopyrightElement:
                    fileHeader.FileName = fileName;
                    fileHeader.CompanyName = docConfig.CompanyName;
                    fileHeader.CopyrightText = docConfig.Copyright;
                    fileHeader.Summary = string.IsNullOrEmpty(fileHeader.Summary) ? summaryText : fileHeader.Summary;
                    break;

                case UpdateFileHeaderStyle.ReplaceAll:
                    fileHeader.FileName = fileName;
                    fileHeader.CompanyName = docConfig.CompanyName;
                    fileHeader.CopyrightText = docConfig.Copyright;
                    fileHeader.Summary = summaryText;
                    break;

                case UpdateFileHeaderStyle.InsertMissing:
                    fileHeader.FileName = string.IsNullOrEmpty(fileHeader.FileName) ? fileName : fileHeader.FileName;
                    fileHeader.CompanyName = string.IsNullOrEmpty(fileHeader.CompanyName) ? docConfig.CompanyName : fileHeader.CompanyName;
                    fileHeader.CopyrightText = string.IsNullOrEmpty(fileHeader.CopyrightText) ? docConfig.Copyright : fileHeader.CopyrightText;
                    fileHeader.Summary = string.IsNullOrEmpty(fileHeader.Summary) ? summaryText : fileHeader.Summary;
                    break;
            }

            fileHeader.Update();
        }
        /// <summary>
        /// Returns a config object exposing the current config settings for this file.
        /// </summary>
        /// <param name="file">
        /// The file to get the config for.
        /// </param>
        /// <returns>
        /// The configuration for the given file.
        /// </returns>
        public DocumentationRulesConfiguration GetDocumentationRulesConfig(ICSharpFile file)
        {
            int hashCode = file.GetSourceFile().GetHashCode();

            if (!this.docConfigFiles.ContainsKey(hashCode))
            {
                DocumentationRulesConfiguration a = new DocumentationRulesConfiguration(file.GetSourceFile());
                this.docConfigFiles.Add(hashCode, a);
            }

            return (DocumentationRulesConfiguration)this.docConfigFiles[hashCode];
        }
        /// <summary>
        /// Returns appropriate text for the file header summary element. It either uses text that it found from the summary of the first type in the file or if 
        /// that is not there it will use the name of the first type in the file.
        /// </summary>
        /// <param name="file">
        /// The file to produce the summary for.
        /// </param>
        /// <returns>
        /// A string of summary text. Empty if we're not inserting text from our settings.
        /// </returns>
        public static string GetSummaryText(ICSharpFile file)
        {
            if (file == null)
            {
                return string.Empty;
            }

            IContextBoundSettingsStore settingsStore = file.GetSourceFile().GetSettingsStore();
            if (!settingsStore.GetValue((StyleCopOptionsSettingsKey key) => key.InsertTextIntoDocumentation))
            {
                return string.Empty;
            }

            string fileName = file.GetSourceFile().ToProjectFile().Location.Name;

            string firstTypeName = GetFirstTypeName(file);

            string firstTypeSummaryText = GetSummaryForDeclaration(GetFirstType(file));

            string summaryText;

            if (string.IsNullOrEmpty(firstTypeSummaryText))
            {
                summaryText = string.IsNullOrEmpty(firstTypeName) ? fileName : string.Format("Defines the {0} type.", firstTypeName);
            }
            else
            {
                summaryText = firstTypeSummaryText;
            }

            return summaryText;
        }
示例#15
0
 /// <summary>
 /// Returns a config object exposing the current config settings for this file.
 /// </summary>
 /// <param name="lifetime">
 /// The lifetime of the settings for the configuration.
 /// </param>
 /// <param name="file">
 /// The file to get the config for.
 /// </param>
 /// <returns>
 /// The configuration for the given file.
 /// </returns>
 private static DocumentationRulesConfiguration GetDocumentationRulesConfig(Lifetime lifetime, ICSharpFile file)
 {
     // TODO: We shouldn't have to resort to service locator!
     var api = file.GetSolution().GetComponent<StyleCopApiPool>().GetInstance(lifetime);
     return new DocumentationRulesConfiguration(api.Settings, file.GetSourceFile());
 }
示例#16
0
        /// <summary>
        /// Inserts any missing items from the file header.
        /// Also formats the existing header ensuring that the top and bottom line start with 2 slashes and a space and that a newline follows the header.
        /// </summary>
        /// <param name="file">
        /// The file to update.
        /// </param>
        /// <param name="analyzerSettings">
        /// The analyzer Settings.
        /// </param>
        private static void UpdateFileHeader(ICSharpFile file, AnalyzerSettings analyzerSettings)
        {
            // The idea here is to load the existing header into our FileHeader object
            // The FileHeader object will ensure that the format of the header is correct even if we're not changing its contents
            // Thus we'll swap it out if its changed at the end.
            string fileName = file.GetSourceFile().ToProjectFile().Location.Name;

            // TODO: How do we handle updating the file header?
            // From the main options page?
            // Actually, looks like ReplaceCopyrightElement is the best option. It fixes the filename,
            // the company name and the copyright, and it'll update the summary, if it isn't already set.
            UpdateFileHeaderStyle updateFileHeaderOption = UpdateFileHeaderStyle.ReplaceCopyrightElement;

            if (updateFileHeaderOption == UpdateFileHeaderStyle.Ignore)
            {
                return;
            }

            Lifetimes.Using(
                lifetime =>
                    {
                        DocumentationRulesConfiguration docConfig = GetDocumentationRulesConfig(lifetime, file);
                        string summaryText = Utils.GetSummaryText(file);
                        FileHeader fileHeader = new FileHeader(file) { InsertSummary = analyzerSettings.IsRuleEnabled("FileHeaderMustHaveSummary") };

                        switch (updateFileHeaderOption)
                        {
                            case UpdateFileHeaderStyle.ReplaceCopyrightElement:
                                fileHeader.FileName = fileName;
                                fileHeader.CompanyName = docConfig.CompanyName;
                                fileHeader.CopyrightText = docConfig.Copyright;
                                fileHeader.Summary = string.IsNullOrEmpty(fileHeader.Summary) ? summaryText : fileHeader.Summary;
                                break;

                            case UpdateFileHeaderStyle.ReplaceAll:
                                fileHeader.FileName = fileName;
                                fileHeader.CompanyName = docConfig.CompanyName;
                                fileHeader.CopyrightText = docConfig.Copyright;
                                fileHeader.Summary = summaryText;
                                break;

                            case UpdateFileHeaderStyle.InsertMissing:
                                fileHeader.FileName = string.IsNullOrEmpty(fileHeader.FileName) ? fileName : fileHeader.FileName;
                                fileHeader.CompanyName = string.IsNullOrEmpty(fileHeader.CompanyName) ? docConfig.CompanyName : fileHeader.CompanyName;
                                fileHeader.CopyrightText = string.IsNullOrEmpty(fileHeader.CopyrightText) ? docConfig.Copyright : fileHeader.CopyrightText;
                                fileHeader.Summary = string.IsNullOrEmpty(fileHeader.Summary) ? summaryText : fileHeader.Summary;
                                break;
                        }

                        fileHeader.Update();
                    });
        }
        /// <summary>
        /// Returns appropriate text for the file header summary element. It either uses text that it found from the summary of the first type in the file or if 
        /// that is not there it will use the name of the first type in the file.
        /// </summary>
        /// <param name="file">
        /// The file to produce the summary for.
        /// </param>
        /// <returns>
        /// A string of summary text. Empty if we're not inserting text from our settings.
        /// </returns>
        public static string GetSummaryText(ICSharpFile file)
        {
            if (!StyleCopOptions.Instance.InsertTextIntoDocumentation)
            {
                return string.Empty;
            }

            string fileName = file.GetSourceFile().ToProjectFile().Location.Name;

            string firstTypeName = Utils.GetFirstTypeName(file);

            string firstTypeSummaryText = Utils.GetSummaryForDeclaration(Utils.GetFirstType(file));

            string summaryText;

            if (string.IsNullOrEmpty(firstTypeSummaryText))
            {
                summaryText = string.IsNullOrEmpty(firstTypeName) ? fileName : string.Format("Defines the {0} type.", firstTypeName);
            }
            else
            {
                summaryText = firstTypeSummaryText;
            }

            return summaryText;
        }
示例#18
0
 /// <summary>
 /// Returns a config object exposing the current config settings for this file.
 /// </summary>
 /// <param name="file">
 /// The file to get the config for.
 /// </param>
 /// <returns>
 /// The configuration for the given file.
 /// </returns>
 public DocumentationRulesConfiguration GetDocumentationRulesConfig(ICSharpFile file)
 {
     // TODO: We shouldn't have to resort to service locator!
     var bootstrapper = Shell.Instance.GetComponent<StyleCopBootstrapper>();
     return new DocumentationRulesConfiguration(bootstrapper.Settings, file.GetSourceFile());
 }