Esempio n. 1
0
 public void BaseInitialize()
 {
     Configuration = new OrderUsingsConfiguration
     {
         GroupsAndSpaces = GetRules()
     };
 }
Esempio n. 2
0
 /// <summary>
 /// Recursively walk namespace declaration blocks, cleaning any import lists they
 /// contain.
 /// </summary>
 /// <param name="namespaceDeclarationNodes">The namespace declaration blocks
 /// to check.</param>
 /// <param name="configuration">The configuration defining the correct order
 /// and spacing.</param>
 private void WalkNamespaceDeclarations(
     TreeNodeCollection <ICSharpNamespaceDeclaration> namespaceDeclarationNodes,
     OrderUsingsConfiguration configuration)
 {
     foreach (var ns in namespaceDeclarationNodes)
     {
         CleanUsings(ns, configuration);
         WalkNamespaceDeclarations(ns.NamespaceDeclarations, configuration);
     }
 }
Esempio n. 3
0
        /// <summary>
        /// Invoked by ReSharper each time it wants us to perform some background processing
        /// of a file.
        /// </summary>
        /// <param name="process">Provides information about and services relating to the
        /// work we are being asked to do.</param>
        /// <param name="settings">Settings information.</param>
        /// <param name="processKind">The kind of processing we're being asked to do.</param>
        /// <param name="file">The file to be processed.</param>
        /// <returns>A process object representing the work, or null if no work will be done.</returns>
        protected override IDaemonStageProcess CreateProcess(
            IDaemonProcess process,
            IContextBoundSettingsStore settings,
            DaemonProcessKind processKind,
            ICSharpFile file)
        {
            if (process == null)
            {
                throw new ArgumentNullException("process");
            }

            // StyleCop's daemon stage looks for a processKind of DaemonProcessKind.OTHER
            // and does nothing (returns null) if it sees it. This turns out to prevent
            // highlights from showing up when you ask ReSharper to inspect code issues
            // across the whole solution. I'm not sure why StyleCop deliberately opts out
            // of it. Perhaps something goes horribly wrong, but I've not seen any sign
            // of that yet, and we really do want solution-wide inspection to work.

            try
            {
                // I guess the base class checks that this is actually a C# file?
                if (!IsSupported(process.SourceFile))
                {
                    return(null);
                }

                // StyleCop checks to see if there are already any errors in the file, and if
                // there are, it decides to do nothing.
                // TODO: Do we need to do that?

                // TODO: We should probably check for exemptions, e.g. generated source files.
            }
            catch (ProcessCancelledException)
            {
                return(null);
            }

            // TODO: should we get an injected ISettingsOptimization?
            var orderUsingSettings =
                settings.GetKey <OrderUsingsSettings>(SettingsOptimization.DoMeSlowly);

            OrderUsingsConfiguration config = null;

            if (!string.IsNullOrWhiteSpace(orderUsingSettings.OrderSpecificationXml))
            {
                config = ConfigurationSerializer.FromXml(new StringReader(orderUsingSettings.OrderSpecificationXml));
            }

            return(new OrderUsingsDaemonStageProcess(process, file, config));
        }
Esempio n. 4
0
        /// <inheritdoc/>
        public void Process(
            IPsiSourceFile sourceFile,
            IRangeMarker rangeMarker,
            CodeCleanupProfile profile,
            IProgressIndicator progressIndicator)
        {
            IPsiServices psiServices            = sourceFile.GetPsiServices();
            IPsiFiles    psiFiles               = psiServices.Files;
            IContextBoundSettingsStore settings = sourceFile.GetSettingsStore();
            var orderUsingSettings              =
                settings.GetKey <OrderUsingsSettings>(SettingsOptimization.DoMeSlowly);
            OrderUsingsConfiguration config = null;

            if (!string.IsNullOrWhiteSpace(orderUsingSettings.OrderSpecificationXml))
            {
                config = ConfigurationSerializer.FromXml(new StringReader(orderUsingSettings.OrderSpecificationXml));
            }

            if (config == null)
            {
                return;
            }

            var file = psiFiles.GetDominantPsiFile <CSharpLanguage>(sourceFile) as ICSharpFile;

            if (file == null)
            {
                return;
            }

            if (!profile.GetSetting(DescriptorInstance))
            {
                return;
            }

            file.GetPsiServices().Transactions.Execute(
                "Code cleanup",
                () =>
            {
                using (_shellLocks.UsingWriteLock())
                {
                    CleanUsings(file, config);
                    WalkNamespaceDeclarations(file.NamespaceDeclarations, config);
                }
            });
        }
Esempio n. 5
0
        /// <summary>
        /// Takes a configuration and a description of a using directive list, and
        /// produces two things: a list containing just the directives (with the
        /// items representing blank lines removed), and a description of the
        /// correct order and grouping for these items for the given configuration.
        /// </summary>
        /// <param name="configuration">The configuration that will determine the
        /// correct order and grouping.</param>
        /// <param name="items">A list of using directives and the blank lines
        /// interspersed therein. (To simplify processing, this may be null to
        /// represent the absence of any using directives.)</param>
        /// <param name="imports">The 'flattened' list (just the using directives,
        /// with any blank lines stripped out) will be written to this argument,
        /// unless <c>items</c> is null, in which case this will be set to null.</param>
        /// <param name="requiredOrderByGroups">The correct ordering and spacing
        /// for the using directives (as determined by the configuration) will be
        /// written to this argument (unless <c>items</c> is null, in which case
        /// this will be set to null).</param>
        /// <remarks>
        /// The correct order and spacing is represented as a list of lists. Each
        /// nested list represents a group of usings, where each group should be
        /// separated by a blank line.
        /// </remarks>
        public static void FlattenImportsAndDetermineOrderAndSpacing(
            OrderUsingsConfiguration configuration,
            List <UsingDirectiveOrSpace> items,
            out List <UsingDirective> imports,
            out List <List <UsingDirective> > requiredOrderByGroups)
        {
            imports = null;
            requiredOrderByGroups = null;
            if (items != null)
            {
                imports = items
                          .Where(i => !i.IsBlankLine)
                          .Select(i => i.Directive)
                          .ToList();

                requiredOrderByGroups =
                    OrderAndSpacingGenerator.DetermineOrderAndSpacing(imports, configuration);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Fixes the order of the using directives in a given file or namespace block
        /// to match the specified configuration.
        /// </summary>
        /// <param name="holder">The file or namespace block in which to fix the order
        /// of using directives (if any are present).</param>
        /// <param name="configuration">The configuration determining the correct order.</param>
        public static void FixOrder(
            ICSharpTypeAndNamespaceHolderDeclaration holder,
            OrderUsingsConfiguration configuration)
        {
            // The reordering proceeds one item at a time, so we just keep reapplying it
            // until there's nothing left to do.
            // To avoid hanging VS in the event that an error in the logic causes the
            // sequence of modifications not to terminate, we ensure we don't try to
            // apply more changes than there are using directives.
            int tries     = 0;
            int itemCount = 0;

            while (tries == 0 || tries <= itemCount)
            {
                List <UsingDirectiveOrSpace>  items = ImportReader.ReadImports(holder);
                List <UsingDirective>         imports;
                List <List <UsingDirective> > requiredOrderByGroups;
                ImportInspector.FlattenImportsAndDetermineOrderAndSpacing(
                    configuration, items, out imports, out requiredOrderByGroups);

                if (requiredOrderByGroups == null)
                {
                    break;
                }

                itemCount = imports.Count;
                Relocation nextChange = ImportInspector.GetNextUsingToMove(requiredOrderByGroups, imports);
                if (nextChange != null)
                {
                    IUsingDirective toMove = holder.Imports[nextChange.From];
                    IUsingDirective before = holder.Imports[nextChange.To];
                    holder.RemoveImport(toMove);
                    holder.AddImportBefore(toMove, before);
                    tries += 1;
                }
                else
                {
                    break;
                }
            }
        }
 /// <summary>
 /// Initializes a <see cref="BaseHighlighting"/>.
 /// </summary>
 /// <param name="typeAndNamespaceHolder">The file or namespace block that contains
 /// the import list being highlighted.</param>
 /// <param name="config">The configuration that was active when we determined that
 /// the import list does not match the requirements.</param>
 internal BaseHighlighting(
     ICSharpTypeAndNamespaceHolderDeclaration typeAndNamespaceHolder, OrderUsingsConfiguration config)
 {
     _config = config;
     _typeAndNamespaceHolder = typeAndNamespaceHolder;
 }
Esempio n. 8
0
        /// <summary>
        /// Fixes the spacing of the using directives in a given file or namespace block
        /// to match the specified configuration. (The directives must already be in
        /// the correct order.)
        /// </summary>
        /// <param name="holder">The file or namespace block in which to fix the spacing
        /// of using directives (if any are present).</param>
        /// <param name="configuration">The configuration determining the correct spacing.</param>
        public static void FixSpacing(
            ICSharpTypeAndNamespaceHolderDeclaration holder,
            OrderUsingsConfiguration configuration)
        {
            // The reordering proceeds one item at a time, so we just keep reapplying it
            // until there's nothing left to do.
            // To avoid hanging VS in the event that an error in the logic causes the
            // sequence of modifications not to terminate, we ensure we don't try to
            // apply more changes than there are either using directives or blank
            // lines in the usings list.
            int tries     = 0;
            int itemCount = 0;

            while (tries == 0 || tries <= itemCount)
            {
                List <UsingDirectiveOrSpace> items = ImportReader.ReadImports(holder);
                if (items == null)
                {
                    return;
                }

                itemCount = items.Count;
                List <UsingDirective>         imports;
                List <List <UsingDirective> > requiredOrderByGroups;
                ImportInspector.FlattenImportsAndDetermineOrderAndSpacing(
                    configuration, items, out imports, out requiredOrderByGroups);

                SpaceChange nextChange = ImportInspector.GetNextSpacingModification(requiredOrderByGroups, items);
                if (nextChange != null)
                {
                    IUsingDirective usingBeforeSpace = holder.Imports[nextChange.Index - 1];
                    if (nextChange.ShouldInsert)
                    {
                        using (WriteLockCookie.Create())
                        {
                            var newLineText = new StringBuffer("\r\n");

                            LeafElementBase newLine = TreeElementFactory.CreateLeafElement(
                                CSharpTokenType.NEW_LINE, newLineText, 0, newLineText.Length);
                            LowLevelModificationUtil.AddChildAfter(usingBeforeSpace, newLine);
                        }
                    }
                    else
                    {
                        var syb = usingBeforeSpace.NextSibling;
                        for (; syb != null && !(syb is IUsingDirective); syb = syb.NextSibling)
                        {
                            if (syb.NodeType == CSharpTokenType.NEW_LINE)
                            {
                                LowLevelModificationUtil.DeleteChild(syb);
                            }
                        }
                    }
                }
                else
                {
                    break;
                }

                tries += 1;
            }
        }
Esempio n. 9
0
 /// <summary>
 /// Initializes a <see cref="UsingOrderHighlighting"/>.
 /// </summary>
 /// <param name="typeAndNamespaceHolder">The file or namespace block that contains
 /// the import list being highlighted.</param>
 /// <param name="config">The configuration that was active when we determined that
 /// the import list does not match the requirements.</param>
 internal UsingSpacingHighlighting(
     ICSharpTypeAndNamespaceHolderDeclaration typeAndNamespaceHolder, OrderUsingsConfiguration config)
     : base(typeAndNamespaceHolder, config)
 {
 }
Esempio n. 10
0
        /// <summary>
        /// Calculates how using directives should be ordered and, where appropriate,
        /// split into groups separated by blank lines.
        /// </summary>
        /// <param name="directives">The directives for which to determine the order
        /// and spacing.</param>
        /// <param name="configuration">The configuration settings describing the
        /// required ordering and spacing.</param>
        /// <returns>A list of lists. This will be empty if the input list was empty.
        /// Otherwise there will be at least one list; if the rules require that any
        /// of the directives be separated by spaces this will be indicated by
        /// returning multiple lists - a blank line should appear between each of
        /// the lists. Within each of the nested lists returned, the directives are
        /// in the order they should appear.</returns>
        public static List <List <UsingDirective> > DetermineOrderAndSpacing(
            IEnumerable <UsingDirective> directives, OrderUsingsConfiguration configuration)
        {
            if (directives == null)
            {
                throw new ArgumentNullException("directives");
            }

            Dictionary <GroupRule, Predicate <UsingDirective> > groupNamespaceMatchers = configuration.GroupsAndSpaces
                                                                                         .Where(gs => !gs.IsSpace)
                                                                                         .ToDictionary <ConfigurationRule, GroupRule, Predicate <UsingDirective> >(
                gs => gs.Rule,
                gs =>
            {
                Regex nsRegex       = null;
                Regex aliasRegex    = null;
                MatchType matchType = gs.Rule.Type;
                switch (matchType)
                {
                case MatchType.Import:
                    nsRegex = RegexForPattern(gs.Rule.NamespacePattern);
                    break;

                case MatchType.Alias:
                    aliasRegex = RegexForPattern(gs.Rule.AliasPattern);
                    break;

                case MatchType.ImportOrAlias:
                    nsRegex    = RegexForPattern(gs.Rule.NamespacePattern);
                    aliasRegex = RegexForPattern(gs.Rule.AliasPattern);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                return(directive =>
                {
                    bool hasAlias = directive.Alias != null;
                    if (matchType == MatchType.Alias && !hasAlias)
                    {
                        return false;
                    }

                    if (matchType == MatchType.Import && hasAlias)
                    {
                        return false;
                    }

                    return
                    (nsRegex == null || nsRegex.IsMatch(directive.Namespace)) &&
                    (aliasRegex == null || !hasAlias || aliasRegex.IsMatch(directive.Alias));
                });
            });

            ILookup <GroupRule, UsingDirective> directivesByGroup = directives.ToLookup(
                d => groupNamespaceMatchers
                .Where(e => e.Value(d))
                .OrderBy(e => e.Key.Priority)
                .First().Key);

            List <UsingDirective> currentItemSet = null;
            var       results  = new List <List <UsingDirective> >();
            GroupRule lastRule = null;

            foreach (ConfigurationRule ruleEntry in configuration.GroupsAndSpaces)
            {
                if (ruleEntry.IsSpace)
                {
                    MakeGroupFromCurrentItemsIfAny(ref currentItemSet, lastRule, results);
                }
                else
                {
                    UsingComparer comparer = ruleEntry.Rule.OrderAliasesBy == OrderAliasBy.Alias ?
                                             CompareByAlias : CompareByNamespace;
                    if (currentItemSet == null)
                    {
                        currentItemSet = new List <UsingDirective>();
                    }

                    currentItemSet.AddRange(directivesByGroup[ruleEntry.Rule].OrderBy(d => d, comparer));
                    lastRule = ruleEntry.Rule;
                }
            }

            MakeGroupFromCurrentItemsIfAny(ref currentItemSet, lastRule, results);

            return(results);
        }
Esempio n. 11
0
 /// <summary>
 /// Initializes a <see cref="OrderUsingsDaemonStageProcess"/>.
 /// </summary>
 /// <param name="process">The process object supplied by R# for this work.</param>
 /// <param name="file">The file to process.</param>
 /// <param name="config">The order and spacing configuration to use.</param>
 public OrderUsingsDaemonStageProcess(IDaemonProcess process, ICSharpFile file, OrderUsingsConfiguration config)
 {
     _file         = file;
     _config       = config;
     DaemonProcess = process;
 }
Esempio n. 12
0
 /// <summary>
 /// Fixes the order and spacing for the using blocks in a file or namespace declaration block.
 /// </summary>
 /// <param name="holder">The file or namespace declaration blocks to check.</param>
 /// <param name="configuration">The configuration defining the correct order
 /// and spacing.</param>
 private void CleanUsings(
     ICSharpTypeAndNamespaceHolderDeclaration holder, OrderUsingsConfiguration configuration)
 {
     Fixes.FixOrder(holder, configuration);
     Fixes.FixSpacing(holder, configuration);
 }