/// <summary> /// Checks an import list against the configured ordering and spacing. /// </summary> /// <param name="holder">The import list container - either a file, or a namespace /// declaration block.</param> /// <param name="highlights">If the import does not meet the configured requirements, /// we allocate a list containing a highlight describing the problem and return /// it via this argument. (We allocate the list on demand to avoid allocations /// in the happy path in which all the import lists are correctly ordered and /// spaced.)</param> private void CheckImports( ICSharpTypeAndNamespaceHolderDeclaration holder, ref List <HighlightingInfo> highlights) { List <UsingDirectiveOrSpace> items = ImportReader.ReadImports(holder); List <UsingDirective> imports; List <List <UsingDirective> > requiredOrderByGroups; ImportInspector.FlattenImportsAndDetermineOrderAndSpacing( _config, items, out imports, out requiredOrderByGroups); bool orderIsCorrect = true; if (requiredOrderByGroups != null) { Relocation nextChange = ImportInspector.GetNextUsingToMove(requiredOrderByGroups, imports); if (nextChange != null) { orderIsCorrect = false; AddHighlight(holder, ref highlights, new UsingOrderHighlighting(holder, _config)); } } // If (and only if) the order is correct, we go on to check the spacing. if (orderIsCorrect) { SpaceChange nextChange = ImportInspector.GetNextSpacingModification(requiredOrderByGroups, items); if (nextChange != null) { AddHighlight(holder, ref highlights, new UsingSpacingHighlighting(holder, _config)); } } }
public static void AddMissingNamespaceImport(ICSharpTypeAndNamespaceHolderDeclaration importScope, CSharpElementFactory factory, string importName) { var importedNamespace = GetNamespace(factory, importName); if (!UsingUtil.CheckAlreadyImported(importScope, importedNamespace)) { UsingUtil.AddImportTo(importScope, importedNamespace); } }
private void AnalyzeTypeAndNamespaceHolder(ICSharpTypeAndNamespaceHolderDeclaration psiFile, IPsiSourceFile psiSourceFile) { foreach (var typeDecl in psiFile.TypeDeclarations) { AnalyzeType(typeDecl, psiSourceFile); } foreach (var nsDecl in psiFile.NamespaceDeclarations) { AnalyzeTypeAndNamespaceHolder(nsDecl, psiSourceFile); } }
private void AddHighlight( ICSharpTypeAndNamespaceHolderDeclaration holder, ref List <HighlightingInfo> highlights, IHighlighting highlight) { if (highlights == null) { highlights = new List <HighlightingInfo>(); } highlights.Add(new HighlightingInfo( holder.ImportsList.GetHighlightingRange(), highlight)); }
/// <summary> /// Handles the removal of an import directive. /// </summary> /// <param name="psiServices">The PSI services.</param> /// <param name="scope">The namespace scope.</param> /// <param name="usingDirective">The using directive to remove.</param> /// <param name="action">The action to perform to remove the directive.</param> public void HandleRemoveImport(IPsiServices psiServices, ICSharpTypeAndNamespaceHolderDeclaration scope, IUsingDirective usingDirective, Action action) { ICSharpTreeNode namespaceNode = usingDirective.GetUsedNamespaceNode(); if (namespaceNode == null) { Assertion.Fail("Only a namespace using can be removed."); } else { TreeTextRange range = namespaceNode.GetTreeTextRange(); HandleRemoveImportInternal(psiServices, scope, usingDirective, action, CSharpLanguage.Instance, range); } }
private static void ProcessImports( IList <IUsingDirective> newImportsList, AlphabeticalUsingsStyle organiseUsingsFormatOption, ExpandUsingsStyle expandUsingsFormatOption, ICSharpTypeAndNamespaceHolderDeclaration declaration) { if (newImportsList == null || newImportsList.Count == 0) { return; } List <IUsingDirective> arrayList = new List <IUsingDirective>(); arrayList.AddRange(newImportsList); if (organiseUsingsFormatOption == AlphabeticalUsingsStyle.Alphabetical) { arrayList.Sort(new UsingStatementSorter()); } foreach (IUsingDirective directive in arrayList) { IUsingDirective newUsingDirective; if (expandUsingsFormatOption == ExpandUsingsStyle.FullyQualify) { if (directive is IUsingAliasDirective) { IUsingAliasDirective aliasDirective = directive as IUsingAliasDirective; newUsingDirective = CSharpElementFactory.GetInstance(declaration.GetPsiModule()) .CreateUsingDirective(aliasDirective.AliasName + " = " + directive.GetFullyQualifiedNamespace()); IUsingAliasDirective n = newUsingDirective as IUsingAliasDirective; n.SetImportedSymbolName(aliasDirective.ImportedSymbolName); } else { newUsingDirective = CSharpElementFactory.GetInstance(declaration.GetPsiModule()).CreateUsingDirective(directive.GetFullyQualifiedNamespace()); } } else { newUsingDirective = directive.CopyWithResolve(); } declaration.RemoveImport(directive); declaration.AddImportBefore(newUsingDirective, null); } }
public Patterns GetPattern(IContextBoundSettingsStore store, ICSharpTypeAndNamespaceHolderDeclaration declaration) { if (!declaration.GetSolution().HasUnityReference()) { return(null); } try { var pattern = store.GetValue((AdditionalFileLayoutSettings s) => s.Pattern); return(FileLayoutUtil.ParseFileLayoutPattern(pattern)); } catch (Exception ex) { Logger.LogException(ex); return(null); } }
/// <inheritdoc/> protected override Action <ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress) { return(textControl => { using (solution.GetComponent <DocumentTransactionManager>() .CreateTransactionCookie(DefaultAction.Commit, "action name")) { var services = solution.GetPsiServices(); services.Transactions.Execute( "Code cleanup", () => services.Locks.ExecuteWithWriteLock(() => { ICSharpTypeAndNamespaceHolderDeclaration holder = _highlighting.TypeAndNamespaceHolder; Fixes.FixOrder(holder, _highlighting.Config); Fixes.FixSpacing(holder, _highlighting.Config); })); } }); }
/// <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> /// 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> /// Returns a list of using directives and spacing from an element that can contain /// a directive list (i.e., a file, or a namespace block). Returns null if the element /// has no using directives. /// </summary> /// <param name="holder">The file or namespace block.</param> /// <returns>Null if no using directives were present; a <see cref="UsingDirectiveOrSpace"/> /// list otherwise.</returns> internal static List <UsingDirectiveOrSpace> ReadImports(ICSharpTypeAndNamespaceHolderDeclaration holder) { List <UsingDirectiveOrSpace> items = null; foreach (IUsingDirective item in holder.Imports) { if (items == null) { items = new List <UsingDirectiveOrSpace>(); } var alias = item as IUsingAliasDirective; items.Add(new UsingDirectiveOrSpace(new UsingDirective { Namespace = alias == null ? item.ImportedSymbolName.QualifiedName : alias.Alias.Name, Alias = alias == null ? null : alias.AliasName })); var syb = item.NextSibling; bool first = true; for (; syb != null && !(syb is IUsingDirective); syb = syb.NextSibling) { if (syb.NodeType == CSharpTokenType.NEW_LINE) { if (first) { first = false; } else { items.Add(new UsingDirectiveOrSpace()); } } } } return(items); }
/// <summary> /// Returns a list of using directives and spacing from an element that can contain /// a directive list (i.e., a file, or a namespace block). Returns null if the element /// has no using directives. /// </summary> /// <param name="holder">The file or namespace block.</param> /// <returns>Null if no using directives were present; a <see cref="UsingDirectiveOrSpace"/> /// list otherwise.</returns> internal static List<UsingDirectiveOrSpace> ReadImports(ICSharpTypeAndNamespaceHolderDeclaration holder) { List<UsingDirectiveOrSpace> items = null; foreach (IUsingDirective item in holder.Imports) { if (items == null) { items = new List<UsingDirectiveOrSpace>(); } var alias = item as IUsingAliasDirective; items.Add(new UsingDirectiveOrSpace(new UsingDirective { Namespace = alias == null ? item.ImportedSymbolName.QualifiedName : alias.Alias.Name, Alias = alias == null ? null : alias.AliasName })); var syb = item.NextSibling; bool first = true; for (; syb != null && !(syb is IUsingDirective); syb = syb.NextSibling) { if (syb.NodeType == CSharpTokenType.NEW_LINE) { if (first) { first = false; } else { items.Add(new UsingDirectiveOrSpace()); } } } } return items; }
/// <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 UsingOrderHighlighting( ICSharpTypeAndNamespaceHolderDeclaration typeAndNamespaceHolder, OrderUsingsConfiguration config) : base(typeAndNamespaceHolder, config) { }
/// <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; } }
public void HandleRemoveImport(IPsiServices psiServices, ICSharpTypeAndNamespaceHolderDeclaration scope, IUsingDirective usingDirective, Action action) { action(); }
private void AddHighlight( ICSharpTypeAndNamespaceHolderDeclaration holder, ref List<HighlightingInfo> highlights, IHighlighting highlight) { if (highlights == null) { highlights = new List<HighlightingInfo>(); } highlights.Add(new HighlightingInfo( holder.ImportsList.GetHighlightingRange(), highlight)); }
public void HandleRemoveImport(IPsiServices psiServices, ICSharpTypeAndNamespaceHolderDeclaration scope, IUsingDirective usingDirective, Action action) { action(); }
/// <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; }
/// <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; }
/// <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) { }
/// <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); }
/// <summary> /// Checks an import list against the configured ordering and spacing. /// </summary> /// <param name="holder">The import list container - either a file, or a namespace /// declaration block.</param> /// <param name="highlights">If the import does not meet the configured requirements, /// we allocate a list containing a highlight describing the problem and return /// it via this argument. (We allocate the list on demand to avoid allocations /// in the happy path in which all the import lists are correctly ordered and /// spaced.)</param> private void CheckImports( ICSharpTypeAndNamespaceHolderDeclaration holder, ref List<HighlightingInfo> highlights) { List<UsingDirectiveOrSpace> items = ImportReader.ReadImports(holder); List<UsingDirective> imports; List<List<UsingDirective>> requiredOrderByGroups; ImportInspector.FlattenImportsAndDetermineOrderAndSpacing( _config, items, out imports, out requiredOrderByGroups); bool orderIsCorrect = true; if (requiredOrderByGroups != null) { Relocation nextChange = ImportInspector.GetNextUsingToMove(requiredOrderByGroups, imports); if (nextChange != null) { orderIsCorrect = false; AddHighlight(holder, ref highlights, new UsingOrderHighlighting(holder, _config)); } } // If (and only if) the order is correct, we go on to check the spacing. if (orderIsCorrect) { SpaceChange nextChange = ImportInspector.GetNextSpacingModification(requiredOrderByGroups, items); if (nextChange != null) { AddHighlight(holder, ref highlights, new UsingSpacingHighlighting(holder, _config)); } } }
private static void ProcessImports( IList <IUsingDirective> originalImportsList, bool organiseUsings, bool expandUsings, ICSharpTypeAndNamespaceHolderDeclaration declaration) { if (originalImportsList == null || originalImportsList.Count == 0) { return; } List <IUsingDirective> sortedImportsList = new List <IUsingDirective>(); sortedImportsList.AddRange(originalImportsList); if (organiseUsings) { sortedImportsList.Sort(new UsingStatementSorter()); } bool alreadySorted = true; bool alreadyExpanded = true; for (int i = 0; i < originalImportsList.Count; i++) { if (originalImportsList[i] != sortedImportsList[i]) { alreadySorted = false; break; } IUsingAliasDirective aliasDirective = originalImportsList[i] as IUsingAliasDirective; if (aliasDirective != null) { if (aliasDirective.ImportedSymbolName.GetText() != aliasDirective.GetFullyQualifiedNamespace()) { alreadyExpanded = false; break; } } } if (alreadySorted && alreadyExpanded) { return; } foreach (IUsingDirective directive in sortedImportsList) { IUsingDirective newUsingDirective; if (expandUsings) { if (directive is IUsingAliasDirective) { IUsingAliasDirective aliasDirective = directive as IUsingAliasDirective; newUsingDirective = CSharpElementFactory.GetInstance(declaration.GetPsiModule()) .CreateUsingDirective(aliasDirective.AliasName + " = " + directive.GetFullyQualifiedNamespace()); IUsingAliasDirective n = newUsingDirective as IUsingAliasDirective; n.SetImportedSymbolName(aliasDirective.ImportedSymbolName); } else { newUsingDirective = CSharpElementFactory.GetInstance(declaration.GetPsiModule()).CreateUsingDirective(directive.GetFullyQualifiedNamespace()); } } else { newUsingDirective = directive.CopyWithResolve(); } declaration.RemoveImport(directive); declaration.AddImportBefore(newUsingDirective, null); } }
/// <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; } }
/// <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); }