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)); } } }); }
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)); }
/// <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); }
/// <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); } }); }
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; }
/// <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()); }
/// <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; }
/// <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()); }