public GatherVisitor (BaseRefactoringContext context, SyntaxTree unit, AccessToClosureIssue issueProvider) : base (context) { this.title = context.TranslateString (issueProvider.Title); this.unit = unit; this.issueProvider = issueProvider; }
void CheckSegments(IList <IFormatStringSegment> segments, TextLocation formatStart, IList <Expression> formatArguments, AstNode anchor) { int argumentCount = formatArguments.Count; foreach (var segment in segments) { var errors = segment.Errors.ToList(); var formatItem = segment as FormatItem; if (formatItem != null) { var segmentEnd = new TextLocation(formatStart.Line, formatStart.Column + segment.EndLocation + 1); var segmentStart = new TextLocation(formatStart.Line, formatStart.Column + segment.StartLocation + 1); if (formatItem.Index >= argumentCount) { var outOfBounds = context.TranslateString("The index '{0}' is out of bounds of the passed arguments"); AddIssue(segmentStart, segmentEnd, string.Format(outOfBounds, formatItem.Index)); } if (formatItem.HasErrors) { var errorMessage = string.Join(Environment.NewLine, errors.Select(error => error.Message).ToArray()); string messageFormat; if (errors.Count > 1) { messageFormat = context.TranslateString("Multiple:\n{0}"); } else { messageFormat = context.TranslateString("{0}"); } AddIssue(segmentStart, segmentEnd, string.Format(messageFormat, errorMessage)); } } else if (segment.HasErrors) { foreach (var error in errors) { var errorStart = new TextLocation(formatStart.Line, formatStart.Column + error.StartLocation + 1); var errorEnd = new TextLocation(formatStart.Line, formatStart.Column + error.EndLocation + 1); AddIssue(errorStart, errorEnd, error.Message); } } } }
protected override IEnumerable <CodeAction> GetFixes(BaseRefactoringContext context, Node env, string variableName) { var containingStatement = env.ContainingStatement; // we don't give a fix for these cases since the general fix may not work // lambda in while/do-while/for condition if (containingStatement is WhileStatement || containingStatement is DoWhileStatement || containingStatement is ForStatement) { yield break; } // lambda in for initializer/iterator if (containingStatement.Parent is ForStatement && ((ForStatement)containingStatement.Parent).EmbeddedStatement != containingStatement) { yield break; } Action <Script> action = script => { var newName = LocalVariableNamePicker.PickSafeName( containingStatement.GetParent <EntityDeclaration> (), Enumerable.Range(1, 100).Select(i => variableName + i)); var variableDecl = new VariableDeclarationStatement(null, new SimpleType("var"), newName, new IdentifierExpression(variableName)); if (containingStatement.Parent is BlockStatement || containingStatement.Parent is SwitchSection) { script.InsertBefore(containingStatement, variableDecl); } else { var offset = script.GetCurrentOffset(containingStatement.StartLocation); script.InsertBefore(containingStatement, variableDecl); script.InsertText(offset, "{"); script.InsertText(script.GetCurrentOffset(containingStatement.EndLocation), "}"); script.FormatText(containingStatement.Parent); } var textNodes = new List <AstNode> (); textNodes.Add(variableDecl.Variables.First().NameToken); foreach (var reference in env.GetAllReferences()) { var identifier = new IdentifierExpression(newName); script.Replace(reference.AstNode, identifier); textNodes.Add(identifier); } script.Link(textNodes.ToArray()); }; yield return(new CodeAction(context.TranslateString("Copy to local variable"), action, env.AstNode)); }
CodeAction GetAction(BaseRefactoringContext context, Expression targetExpression, IMember member) { var builder = context.CreateTypeSystemAstBuilder(targetExpression); var newType = builder.ConvertType(member.DeclaringType); string description = string.Format("{0} '{1}'", context.TranslateString("Use base qualifier"), newType.ToString()); return(new CodeAction(description, script => { script.Replace(targetExpression, newType); }, targetExpression)); }
IEnumerable <CodeAction> GetActions(BaseRefactoringContext context, Expression targetExpression, IMember member) { var builder = context.CreateTypeSytemAstBuilder(targetExpression); var newType = builder.ConvertType(member.DeclaringType); string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText()); yield return(new CodeAction(description, script => { script.Replace(targetExpression, newType); })); }
public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) { var parameters = objectCreateExpression.Arguments; if (parameters.Count != 2) { return; } var firstParam = parameters.FirstOrNullObject() as PrimitiveExpression; var secondParam = parameters.LastOrNullObject() as PrimitiveExpression; if (firstParam == null || !(firstParam.Value is string) || secondParam == null || !(secondParam.Value is string)) { return; } var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult; if (type == null) { return; } var leftLength = (firstParam.Value as string).Length; var rightLength = (secondParam.Value as string).Length; Func <int, int, bool> func; if (!rules.TryGetValue(type.Type.FullName, out func)) { return; } if (!func(leftLength, rightLength)) { AddIssue(objectCreateExpression, context.TranslateString("The parameters are in the wrong order"), GetActions(objectCreateExpression, firstParam, secondParam)); } }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); if (!IsCallDependentOnCurrentInstance(invocationExpression)) { // Call within current class scope without 'this' or 'base' return; } var targetMethod = context.Resolve(invocationExpression) as InvocationResolveResult; if (targetMethod == null) { return; } if (targetMethod.IsVirtualCall) { AddIssue(invocationExpression, context.TranslateString("Virtual member call in constructor"), new CodeAction(string.Format(context.TranslateString("Make class '{0}' sealed"), CurrentType.Name), script => script.ChangeModifier(CurrentType, CurrentType.Modifiers | Modifiers.Sealed), invocationExpression)); } }
void HandleMember(Expression issueAnchor, Expression targetExpression, IMember member, ResolveResult targetResolveResult) { var typeResolveResult = targetResolveResult as TypeResolveResult; if (typeResolveResult == null) { return; } if (!member.IsStatic) { return; } if (typeResolveResult.Type.Equals(member.DeclaringType)) { return; } AddIssue(issueAnchor, context.TranslateString("Static method invoked via derived type"), GetActions(context, targetExpression, member)); }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); if (!IsCallDependentOnCurrentInstance(invocationExpression)) { // Call within current class scope without 'this' or 'base' return; } var targetMethod = context.Resolve(invocationExpression) as InvocationResolveResult; if (targetMethod == null) { return; } if (targetMethod.IsVirtualCall) { AddIssue(invocationExpression, context.TranslateString("Constructors should not call virtual members")); } }
protected override IEnumerable<CodeAction> GetFixes(BaseRefactoringContext context, Node env, string variableName) { var containingStatement = env.ContainingStatement; // we don't give a fix for these cases since the general fix may not work // lambda in while/do-while/for condition if (containingStatement is WhileStatement || containingStatement is DoWhileStatement || containingStatement is ForStatement) yield break; // lambda in for initializer/iterator if (containingStatement.Parent is ForStatement && ((ForStatement)containingStatement.Parent).EmbeddedStatement != containingStatement) yield break; Action<Script> action = script => { var newName = LocalVariableNamePicker.PickSafeName ( containingStatement.GetParent<EntityDeclaration> (), Enumerable.Range (1, 100).Select (i => variableName + i)); var variableDecl = new VariableDeclarationStatement (new SimpleType("var"), newName, new IdentifierExpression (variableName)); if (containingStatement.Parent is BlockStatement || containingStatement.Parent is SwitchSection) { script.InsertBefore (containingStatement, variableDecl); } else { var offset = script.GetCurrentOffset (containingStatement.StartLocation); script.InsertBefore (containingStatement, variableDecl); script.InsertText (offset, "{"); script.InsertText (script.GetCurrentOffset (containingStatement.EndLocation), "}"); script.FormatText (containingStatement.Parent); } var textNodes = new List<AstNode> (); textNodes.Add (variableDecl.Variables.First ().NameToken); foreach (var reference in env.GetAllReferences ()) { var identifier = new IdentifierExpression (newName); script.Replace (reference.AstNode, identifier); textNodes.Add (identifier); } script.Link (textNodes.ToArray ()); }; yield return new CodeAction (context.TranslateString ("Copy to local variable"), action, env.AstNode); }
public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) { base.VisitObjectCreateExpression(objectCreateExpression); Expression paramNode; Expression altParamNode; if (!CheckExceptionType(objectCreateExpression, out paramNode, out altParamNode)) { return; } var paramName = GetArgumentParameterName(paramNode); if (paramName == null) { return; } var validNames = GetValidParameterNames(objectCreateExpression); if (!validNames.Contains(paramName)) { // Case 1: Parameter name is swapped var altParamName = GetArgumentParameterName(altParamNode); if (altParamName != null && validNames.Contains(altParamName)) { AddIssue( paramNode, string.Format(context.TranslateString("The parameter '{0}' can't be resolved"), paramName), context.TranslateString("Swap parameter."), script => { var newAltNode = paramNode.Clone(); script.Replace(paramNode, altParamNode.Clone()); script.Replace(altParamNode, newAltNode); } ); AddIssue( altParamNode, context.TranslateString("The parameter name is on the wrong argument."), context.TranslateString("Swap parameter."), script => { var newAltNode = paramNode.Clone(); script.Replace(paramNode, altParamNode.Clone()); script.Replace(altParamNode, newAltNode); } ); return; } var guessName = GuessParameterName(objectCreateExpression, validNames); if (guessName != null) { AddIssue( paramNode, string.Format(context.TranslateString("The parameter '{0}' can't be resolved"), paramName), string.Format(context.TranslateString("Replace with '\"{0}\"'."), guessName), script => { script.Replace(paramNode, new PrimitiveExpression(guessName)); } ); return; } // General case: mark only AddIssue( paramNode, string.Format(context.TranslateString("The parameter '{0}' can't be resolved"), paramName) ); } }
static CodeAction HandleNegatedCase(BaseRefactoringContext ctx, IfElseStatement ifElseStatement, Match match, out IsExpression isExpression, out int foundCastCount) { foundCastCount = 0; var outerIs = match.Get <Expression>("isExpression").Single(); isExpression = CSharpUtil.GetInnerMostExpression(outerIs) as IsExpression; var obj = CSharpUtil.GetInnerMostExpression(isExpression.Expression); var castToType = isExpression.Type; var cast = new Choice { PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastTo(castToType.Clone())), PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastAs(castToType.Clone())) }; var rr = ctx.Resolve(castToType); if (rr == null || rr.IsError || rr.Type.IsReferenceType == false) { return(null); } var foundCasts = ifElseStatement.GetParent <BlockStatement>().DescendantNodes(n => n.StartLocation >= ifElseStatement.StartLocation && !cast.IsMatch(n)).Where(n => cast.IsMatch(n)).ToList(); foundCastCount = foundCasts.Count; return(new CodeAction(ctx.TranslateString("Use 'as' and check for null"), script => { var varName = ctx.GetNameProposal(CreateMethodDeclarationAction.GuessNameFromType(rr.Type), ifElseStatement.StartLocation); var varDec = new VariableDeclarationStatement(new PrimitiveType("var"), varName, new AsExpression(obj.Clone(), castToType.Clone())); var binaryOperatorIdentifier = new IdentifierExpression(varName); var binaryOperatorExpression = new BinaryOperatorExpression(binaryOperatorIdentifier, BinaryOperatorType.Equality, new NullReferenceExpression()); var linkedNodes = new List <AstNode>(); linkedNodes.Add(varDec.Variables.First().NameToken); linkedNodes.Add(binaryOperatorIdentifier); if (IsEmbeddedStatement(ifElseStatement)) { var block = new BlockStatement(); block.Add(varDec); var newIf = (IfElseStatement)ifElseStatement.Clone(); newIf.Condition = binaryOperatorExpression; foreach (var node in newIf.DescendantNodesAndSelf(n => !cast.IsMatch(n)).Where(n => cast.IsMatch(n))) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); node.ReplaceWith(id); } block.Add(newIf); script.Replace(ifElseStatement, block); } else { script.InsertBefore(ifElseStatement, varDec); script.Replace(ifElseStatement.Condition, binaryOperatorExpression); foreach (var c in foundCasts) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); script.Replace(c, id); } } script.Link(linkedNodes); }, isExpression.IsToken)); }
public GatherVisitor(BaseRefactoringContext context, SyntaxTree unit, AccessToClosureIssue qualifierDirectiveEvidentIssueProvider) : base(context, qualifierDirectiveEvidentIssueProvider) { this.title = context.TranslateString(qualifierDirectiveEvidentIssueProvider.Title); }
public string GetErrorMessage(BaseRefactoringContext ctx, string name, out IList <string> suggestedNames) { suggestedNames = new List <string>(); string id = name; string errorMessage = null; bool missingRequiredPrefix = false; bool missingRequiredSuffix = false; string requiredPrefix = null; string allowedPrefix = null; string suffix = null; if (AllowedPrefixes != null && AllowedPrefixes.Length > 0) { allowedPrefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p)); if (allowedPrefix != null) { id = id.Substring(allowedPrefix.Length); } } if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) { requiredPrefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p)); if (requiredPrefix == null) { errorMessage = string.Format(ctx.TranslateString("Name should have prefix '{0}'."), RequiredPrefixes [0]); missingRequiredPrefix = true; } else { id = id.Substring(requiredPrefix.Length); } } else if (ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) { requiredPrefix = ForbiddenPrefixes.FirstOrDefault(p => id.StartsWith(p)); if (requiredPrefix != null) { errorMessage = string.Format(ctx.TranslateString("Name has forbidden prefix '{0}'."), requiredPrefix); id = id.Substring(requiredPrefix.Length); } } if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) { suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s)); if (suffix == null) { errorMessage = string.Format(ctx.TranslateString("Name should have suffix '{0}'."), RequiredSuffixes [0]); missingRequiredSuffix = true; } else { id = id.Substring(0, id.Length - suffix.Length); } } else if (ForbiddenSuffixes != null && ForbiddenSuffixes.Length > 0) { suffix = ForbiddenSuffixes.FirstOrDefault(p => id.EndsWith(p)); if (suffix != null) { errorMessage = string.Format(ctx.TranslateString("Name has forbidden suffix '{0}'."), suffix); id = id.Substring(0, id.Length - suffix.Length); } } switch (NamingStyle) { case NamingStyle.AllLower: if (id.Any(ch => char.IsLetter(ch) && char.IsUpper(ch))) { errorMessage = string.Format(ctx.TranslateString("'{0}' contains upper case letters."), name); suggestedNames.Add(LowerCaseIdentifier(WordParser.BreakWords(id))); } else { suggestedNames.Add(id); } break; case NamingStyle.AllUpper: if (id.Any(ch => char.IsLetter(ch) && char.IsLower(ch))) { errorMessage = string.Format(ctx.TranslateString("'{0}' contains lower case letters."), name); suggestedNames.Add(UpperCaseIdentifier(WordParser.BreakWords(id))); } else { suggestedNames.Add(id); } break; case NamingStyle.CamelCase: if (id.Length > 0 && char.IsUpper(id [0])) { errorMessage = string.Format(ctx.TranslateString("'{0}' should start with a lower case letter."), name); } else if (!NoUnderscoreWithoutNumber(id)) { errorMessage = string.Format(ctx.TranslateString("'{0}' should not separate words with an underscore."), name); } else { suggestedNames.Add(id); break; } suggestedNames.Add(CamelCaseIdentifier(WordParser.BreakWords(id))); break; case NamingStyle.PascalCase: if (id.Length > 0 && char.IsLower(id [0])) { errorMessage = string.Format(ctx.TranslateString("'{0}' should start with an upper case letter."), name); } else if (!NoUnderscoreWithoutNumber(id)) { errorMessage = string.Format(ctx.TranslateString("'{0}' should not separate words with an underscore."), name); } else { suggestedNames.Add(id); break; } suggestedNames.Add(PascalCaseIdentifier(WordParser.BreakWords(id))); break; case NamingStyle.FirstUpper: if (id.Length > 0 && char.IsLower(id [0])) { errorMessage = string.Format(ctx.TranslateString("'{0}' should start with an upper case letter."), name); } else if (id.Take(1).Any(ch => char.IsLetter(ch) && char.IsUpper(ch))) { errorMessage = string.Format(ctx.TranslateString("'{0}' contains an upper case letter after the first."), name); } else { suggestedNames.Add(id); break; } suggestedNames.Add(FirstUpperIdentifier(WordParser.BreakWords(id))); break; } if (requiredPrefix != null) { for (int i = 0; i < suggestedNames.Count; i++) { suggestedNames [i] = requiredPrefix + suggestedNames [i]; } } else if (allowedPrefix != null) { int count = suggestedNames.Count; for (int i = 0; i < count; i++) { suggestedNames.Add(suggestedNames [i]); suggestedNames [i] = allowedPrefix + suggestedNames [i]; } } else if (missingRequiredPrefix) { for (int i = 0; i < suggestedNames.Count; i++) { var n = suggestedNames [i]; bool first = true; foreach (var p in RequiredPrefixes) { if (first) { first = false; suggestedNames [i] = p + n; } else { suggestedNames.Add(p + n); } } } } if (suffix != null) { for (int i = 0; i < suggestedNames.Count; i++) { suggestedNames [i] = suggestedNames [i] + suffix; } } else if (missingRequiredSuffix) { for (int i = 0; i < suggestedNames.Count; i++) { var n = suggestedNames [i]; bool first = true; foreach (var s in RequiredSuffixes) { if (first) { first = false; suggestedNames [i] = n + s; } else { suggestedNames.Add(n + s); } } } } return(errorMessage // should never happen. ?? "no known errors."); }
public GatherVisitor(BaseRefactoringContext context, SyntaxTree unit, AccessToClosureIssue issueProvider) : base(context, issueProvider) { this.title = context.TranslateString(issueProvider.Title); }
IEnumerable<CodeAction> GetActions(BaseRefactoringContext context, Expression targetExpression, IMember member) { var csResolver = context.Resolver.GetResolverStateBefore(targetExpression); var builder = new TypeSystemAstBuilder(csResolver); var newType = builder.ConvertType(member.DeclaringType); string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText()); yield return new CodeAction(description, script => { script.Replace(targetExpression, newType); }); }
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) { base.VisitVariableDeclarationStatement(variableDeclarationStatement); var rootNode = variableDeclarationStatement.Parent as BlockStatement; if (rootNode == null) { // We are somewhere weird, like a the ResourceAquisition of a using statement return; } // TODO: Handle declarations with more than one variable? if (variableDeclarationStatement.Variables.Count > 1) { return; } var variableInitializer = variableDeclarationStatement.Variables.First(); var identifiers = GetIdentifiers(rootNode.Descendants, variableInitializer.Name).ToList(); if (identifiers.Count == 0) { // variable is not used return; } if (!CheckForInvocations(variableInitializer.Initializer)) { return; } AstNode deepestCommonAncestor = GetDeepestCommonAncestor(rootNode, identifiers); var path = GetPath(rootNode, deepestCommonAncestor); // The node that will follow the moved declaration statement AstNode anchorNode = GetInitialAnchorNode(rootNode, identifiers, path); // Restrict path to only those where the initializer has not changed var pathToCheck = path.Skip(1).ToList(); var firstInitializerChangeNode = GetFirstInitializerChange(variableDeclarationStatement, pathToCheck, variableInitializer.Initializer); if (firstInitializerChangeNode != null) { // The node changing the initializer expression may not be on the path // to the actual usages of the variable, so we need to merge the paths // so we get the part of the paths that are common between them var pathToChange = GetPath(rootNode, firstInitializerChangeNode); var deepestCommonIndex = GetLowestCommonAncestorIndex(path, pathToChange); anchorNode = pathToChange [deepestCommonIndex + 1]; path = pathToChange.Take(deepestCommonIndex).ToList(); } // Restrict to locations outside of blacklisted node types var firstBlackListedNode = path.FirstOrDefault(node => moveTargetBlacklist.Contains(node.GetType())); if (firstBlackListedNode != null) { path = GetPath(rootNode, firstBlackListedNode.Parent); anchorNode = firstBlackListedNode; } anchorNode = GetInsertionPoint(anchorNode); if (anchorNode != null && anchorNode != rootNode && anchorNode.Parent != rootNode) { AddIssue(new CodeIssue(variableDeclarationStatement, context.TranslateString("Variable could be moved to a nested scope"), GetActions(variableDeclarationStatement, (Statement)anchorNode))); } }
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) { base.VisitVariableDeclarationStatement(variableDeclarationStatement); if (!(variableDeclarationStatement.Parent is BlockStatement)) { // We are somewhere weird, like a the ResourceAquisition of a using statement return; } if (variableDeclarationStatement.Variables.Count > 1) { return; } // Start at the parent node. Presumably this is a BlockStatement var rootNode = variableDeclarationStatement.Parent; var variableInitializer = variableDeclarationStatement.Variables.First(); var identifiers = GetIdentifiers(rootNode.Descendants, variableInitializer.Name).ToList(); if (identifiers.Count == 0) { // variable is not used return; } AstNode deepestCommonAncestor = GetDeepestCommonAncestor(rootNode, identifiers); var path = GetPath(rootNode, deepestCommonAncestor); // Restrict path to only those where the initializer has not changed var firstInitializerChange = GetFirstInitializerChange(variableDeclarationStatement, path, variableInitializer.Initializer); if (firstInitializerChange != null) { path = GetPath(rootNode, firstInitializerChange); } // Restict to locations outside of blacklisted node types var firstBlackListedNode = (from node in path where moveTargetBlacklist.Contains(node.GetType()) select node).FirstOrDefault(); if (firstBlackListedNode != null) { path = GetPath(rootNode, firstBlackListedNode); } // Get the most nested possible target for the move Statement mostNestedFollowingStatement = null; for (int i = path.Count - 1; i >= 0; i--) { var statement = path[i] as Statement; if (statement != null && (IsScopeContainer(statement.Parent) || IsScopeContainer(statement))) { mostNestedFollowingStatement = statement; break; } } if (mostNestedFollowingStatement != null && mostNestedFollowingStatement != rootNode && mostNestedFollowingStatement.Parent != rootNode) { AddIssue(variableDeclarationStatement, context.TranslateString("Variable could be moved to a nested scope"), GetActions(variableDeclarationStatement, mostNestedFollowingStatement)); } }
public GatherVisitor(BaseRefactoringContext ctx) : base(ctx) { _commandTitle = ctx.TranslateString("';' should be avoided. Use '{}' instead"); }
CodeAction GetAction(BaseRefactoringContext context, Expression targetExpression, IMember member) { var builder = context.CreateTypeSytemAstBuilder(targetExpression); var newType = builder.ConvertType(member.DeclaringType); string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText()); return new CodeAction(description, script => { script.Replace(targetExpression, newType); }); }