DomRegion MakeBraceRegion(AstNode node) { if (node == null || node.IsNull) return DomRegion.Empty; else return MakeRegion(node.GetChildByRole(AstNode.Roles.LBrace).StartLocation, node.GetChildByRole(AstNode.Roles.RBrace).EndLocation); }
private void AddIssue(AstNode node, IType baseType, int argumentCount = 0) { var identifier = node.GetChildByRole(Roles.Identifier); this.AddIssue( identifier, string.Format(ctx.TranslateString("CS1729: The type '{0}' does not contain a constructor that takes '{1}' arguments"), baseType.Name, argumentCount)); }
public static ResolveResult Resolve(Lazy<ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = syntaxTree.GetNodeAt(location); if (node == null || node is ArrayInitializerExpression) return null; if (CSharpAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer) { Console.WriteLine (2); // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else { return null; } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return null; } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return null; } } if (node == null) return null; if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) { node = node.Parent; } InvocationExpression parentInvocation = null; if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused CSharpAstResolver resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); ResolveResult rr = resolver.Resolve(node, cancellationToken); if (rr is MethodGroupResolveResult && parentInvocation != null) return resolver.Resolve(parentInvocation); else return rr; }
static bool IsAsync(AstNode currentFunction) { var method = currentFunction as MethodDeclaration; if (method != null) { return(method.HasModifier(Modifiers.Async)); } return(!currentFunction.GetChildByRole(LambdaExpression.AsyncModifierRole).IsNull); }
static bool HasNoIdentifier(AstNode node) { return (node.GetChildByRole(Roles.Identifier) == Roles.Identifier.NullObject && node.GetChildByRole(Roles.Parameter) == Roles.Parameter.NullObject && node.GetChildByRole(Roles.Argument) == Roles.Argument.NullObject && node.GetChildByRole(Roles.Type) == Roles.Type.NullObject && node.GetChildByRole(Roles.TargetExpression) == Roles.TargetExpression.NullObject && node.GetChildByRole(Roles.TypeParameter) == Roles.TypeParameter.NullObject && node.GetChildByRole(Roles.TypeArgument) == Roles.TypeArgument.NullObject && node.GetChildByRole(Roles.Constraint) == Roles.Constraint.NullObject); }
public static ResolveResult Resolve(Func<ICompilation> compilation, CSharpParsedFile parsedFile, CompilationUnit cu, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = cu.GetNodeAt(location); if (node == null) return null; if (CSharpAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer) { // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else { return null; } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return null; } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return null; } } if (node == null) return null; if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) { node = node.Parent; } InvocationExpression parentInvocation = null; if (node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } CSharpAstResolver resolver = new CSharpAstResolver(compilation(), cu, parsedFile); resolver.ApplyNavigator(new NodeListResolveVisitorNavigator(node), cancellationToken); ResolveResult rr = resolver.Resolve(node, cancellationToken); if (rr is MethodGroupResolveResult && parentInvocation != null) return resolver.Resolve(parentInvocation); else return rr; }
protected internal override bool DoMatch(AstNode other, Match match) { IdentifierExpression ident = other as IdentifierExpression; if (ident == null || ident.TypeArguments.Any()) { return(false); } AstNode referenced = match.Get(referencedGroupName).Last(); return(ident.Identifier == referenced.GetChildByRole(AstNode.Roles.Identifier).Name); }
NullValueAnalysis GetAnalysis(AstNode parentFunction) { NullValueAnalysis analysis; if (cachedNullAnalysis.TryGetValue(parentFunction, out analysis)) { return(analysis); } analysis = new NullValueAnalysis(ctx, parentFunction.GetChildByRole(Roles.Body), parentFunction.GetChildrenByRole(Roles.Parameter), ctx.CancellationToken); cachedNullAnalysis [parentFunction] = analysis; return(analysis); }
void HandleConstructorOrDestructor(AstNode constructorDeclaration) { Identifier nameToken = constructorDeclaration.GetChildByRole(Roles.Identifier); VisitChildrenUntil(constructorDeclaration, nameToken); var currentTypeDef = resolver.GetResolverStateBefore(constructorDeclaration).CurrentTypeDefinition; if (currentTypeDef != null && nameToken.Name == currentTypeDef.Name) { TColor color; if (TryGetTypeHighlighting(currentTypeDef.Kind, out color)) { Colorize(nameToken, color); } } VisitChildrenAfter(constructorDeclaration, nameToken); }
public string ConvertSymbol(ISymbol symbol) { var stringWriter = new StringWriter(); var astBuilder = new TypeSystemAstBuilder(); astBuilder.AlwaysUseShortTypeNames = true; AstNode node = astBuilder.ConvertSymbol(symbol); var writer = new TextWriterTokenWriter(stringWriter); var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { rt.AcceptVisitor(new CSharpOutputVisitor(stringWriter, FormattingOptionsFactory.CreateMono())); } IProperty property = symbol as IProperty; if (property != null) { writer.Space(); writer.WriteToken(Roles.LBrace, "{"); writer.Space(); if (property.CanGet) { writer.WriteKeyword(PropertyDeclaration.GetKeywordRole, "get"); writer.WriteToken(Roles.Semicolon, ";"); writer.Space(); } if (property.CanSet) { writer.WriteKeyword(PropertyDeclaration.SetKeywordRole, "set"); writer.WriteToken(Roles.Semicolon, ";"); writer.Space(); } writer.WriteToken(Roles.RBrace, "}"); } return(stringWriter.ToString()); }
public override void StartNode(AstNode node) { if (nodeStack.Count == 0) { if (IsUsingDeclaration(node)) { firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling); lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling); } else { firstUsingDeclaration = false; lastUsingDeclaration = false; } } nodeStack.Push(node); startLocations.Push(output.Location); if (node is EntityDeclaration && node.Annotation <MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull) { output.WriteDefinition("", node.Annotation <MemberReference>(), false); } if (node.Annotation <MethodDebugSymbols>() != null) { symbolsStack.Push(node.Annotation <MethodDebugSymbols>()); symbolsStack.Peek().StartLocation = startLocations.Peek(); } }
public void StartNode(AstNode node) { if (nodeStack.Count == 0) { if (IsUsingDeclaration(node)) { firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling); lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling); } else { firstUsingDeclaration = false; lastUsingDeclaration = false; } } nodeStack.Push(node); startLocations.Push(output.Location); if (node is AttributedNode && node.Annotation <MemberReference>() != null && node.GetChildByRole(AstNode.Roles.Identifier).IsNull) { output.WriteDefinition("", node.Annotation <MemberReference>(), false); } MemberMapping mapping = node.Annotation <MemberMapping>(); if (mapping != null) { parentMemberMappings.Push(currentMemberMapping); currentMemberMapping = mapping; } }
public override void StartNode(AstNode node) { if (nodeStack.Count == 0) { if (IsUsingDeclaration(node)) { firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling); lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling); } else { firstUsingDeclaration = false; lastUsingDeclaration = false; } } nodeStack.Push(node); startLocations.Push(output.Location); if (node is EntityDeclaration && node.Annotation<MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull) output.WriteDefinition("", node.Annotation<MemberReference>(), false); if (node.Annotation<MethodDebugSymbols>() != null) { symbolsStack.Push(node.Annotation<MethodDebugSymbols>()); symbolsStack.Peek().StartLocation = startLocations.Peek(); } }
public void ConvertSymbol(ISymbol symbol, TokenWriter writer, CSharpFormattingOptions formattingPolicy) { if (symbol == null) { throw new ArgumentNullException(nameof(symbol)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (formattingPolicy == null) { throw new ArgumentNullException(nameof(formattingPolicy)); } TypeSystemAstBuilder astBuilder = CreateAstBuilder(); AstNode node = astBuilder.ConvertSymbol(symbol); writer.StartNode(node); EntityDeclaration entityDecl = node as EntityDeclaration; if (entityDecl != null) { PrintModifiers(entityDecl.Modifiers, writer); } if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword) { if (node is TypeDeclaration) { switch (((TypeDeclaration)node).ClassType) { case ClassType.Class: writer.WriteKeyword(Roles.ClassKeyword, "class"); break; case ClassType.Struct: writer.WriteKeyword(Roles.StructKeyword, "struct"); break; case ClassType.Interface: writer.WriteKeyword(Roles.InterfaceKeyword, "interface"); break; case ClassType.Enum: writer.WriteKeyword(Roles.EnumKeyword, "enum"); break; case ClassType.RecordClass: writer.WriteKeyword(Roles.RecordKeyword, "record"); break; default: throw new Exception("Invalid value for ClassType"); } writer.Space(); } else if (node is DelegateDeclaration) { writer.WriteKeyword(Roles.DelegateKeyword, "delegate"); writer.Space(); } else if (node is EventDeclaration) { writer.WriteKeyword(EventDeclaration.EventKeywordRole, "event"); writer.Space(); } else if (node is NamespaceDeclaration) { writer.WriteKeyword(Roles.NamespaceKeyword, "namespace"); writer.Space(); } } if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) != ConversionFlags.PlaceReturnTypeAfterParameterList && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) { var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); writer.Space(); } } if (symbol is ITypeDefinition) { WriteTypeDeclarationName((ITypeDefinition)symbol, writer, formattingPolicy); } else if (symbol is IMember) { WriteMemberDeclarationName((IMember)symbol, writer, formattingPolicy); } else { writer.WriteIdentifier(Identifier.Create(symbol.Name)); } if ((ConversionFlags & ConversionFlags.ShowParameterList) == ConversionFlags.ShowParameterList && HasParameters(symbol)) { writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, symbol.SymbolKind == SymbolKind.Indexer ? "[" : "("); bool first = true; foreach (var param in node.GetChildrenByRole(Roles.Parameter)) { if ((ConversionFlags & ConversionFlags.ShowParameterModifiers) == 0) { param.ParameterModifier = ParameterModifier.None; } if ((ConversionFlags & ConversionFlags.ShowParameterDefaultValues) == 0) { param.DefaultExpression.Detach(); } if (first) { first = false; } else { writer.WriteToken(Roles.Comma, ","); writer.Space(); } param.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); } writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.RBracket : Roles.RPar, symbol.SymbolKind == SymbolKind.Indexer ? "]" : ")"); } if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) == ConversionFlags.PlaceReturnTypeAfterParameterList && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) { var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { writer.Space(); writer.WriteToken(Roles.Colon, ":"); writer.Space(); if (symbol is IField f && CSharpDecompiler.IsFixedField(f, out var type, out int elementCount)) { rt = astBuilder.ConvertType(type); new IndexerExpression(new TypeReferenceExpression(rt), astBuilder.ConvertConstantValue(f.Compilation.FindType(KnownTypeCode.Int32), elementCount)) .AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); } else { rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); } } }
public void StartNode(AstNode node) { if (nodeStack.Count == 0) { if (IsUsingDeclaration(node)) { firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling); lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling); } else { firstUsingDeclaration = false; lastUsingDeclaration = false; } } nodeStack.Push(node); startLocations.Push(output.Location); if (node is EntityDeclaration && node.Annotation<MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull) output.WriteDefinition("", node.Annotation<MemberReference>(), false); MemberMapping mapping = node.Annotation<MemberMapping>(); if (mapping != null) { parentMemberMappings.Push(currentMemberMapping); currentMemberMapping = mapping; } }
public void ConvertSymbol(ISymbol symbol, TokenWriter writer, CSharpFormattingOptions formattingPolicy) { if (symbol == null) { throw new ArgumentNullException("symbol"); } if (writer == null) { throw new ArgumentNullException("writer"); } if (formattingPolicy == null) { throw new ArgumentNullException("formattingPolicy"); } TypeSystemAstBuilder astBuilder = CreateAstBuilder(); AstNode node = astBuilder.ConvertSymbol(symbol); EntityDeclaration entityDecl = node as EntityDeclaration; if (entityDecl != null) { PrintModifiers(entityDecl.Modifiers, writer); } if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword) { if (node is TypeDeclaration) { switch (((TypeDeclaration)node).ClassType) { case ClassType.Class: writer.WriteKeyword(Roles.ClassKeyword, "class"); break; case ClassType.Struct: writer.WriteKeyword(Roles.StructKeyword, "struct"); break; case ClassType.Interface: writer.WriteKeyword(Roles.InterfaceKeyword, "interface"); break; case ClassType.Enum: writer.WriteKeyword(Roles.EnumKeyword, "enum"); break; default: throw new Exception("Invalid value for ClassType"); } writer.Space(); } else if (node is DelegateDeclaration) { writer.WriteKeyword(Roles.DelegateKeyword, "delegate"); writer.Space(); } else if (node is EventDeclaration) { writer.WriteKeyword(EventDeclaration.EventKeywordRole, "event"); writer.Space(); } else if (node is NamespaceDeclaration) { writer.WriteKeyword(Roles.NamespaceKeyword, "namespace"); writer.Space(); } } if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) != ConversionFlags.PlaceReturnTypeAfterParameterList && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) { var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); writer.Space(); } } if (symbol is ITypeDefinition) { WriteTypeDeclarationName((ITypeDefinition)symbol, writer, formattingPolicy); } else if (symbol is IMember) { WriteMemberDeclarationName((IMember)symbol, writer, formattingPolicy); } else { writer.WriteIdentifier(Identifier.Create(symbol.Name)); } if ((ConversionFlags & ConversionFlags.ShowParameterList) == ConversionFlags.ShowParameterList && HasParameters(symbol)) { writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, symbol.SymbolKind == SymbolKind.Indexer ? "[" : "("); bool first = true; foreach (var param in node.GetChildrenByRole(Roles.Parameter)) { if (first) { first = false; } else { writer.WriteToken(Roles.Comma, ","); writer.Space(); } param.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); } writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.RBracket : Roles.RPar, symbol.SymbolKind == SymbolKind.Indexer ? "]" : ")"); } if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) == ConversionFlags.PlaceReturnTypeAfterParameterList && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) { var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { writer.Space(); writer.WriteToken(Roles.Colon, ":"); writer.Space(); rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); } } if ((ConversionFlags & ConversionFlags.ShowBody) == ConversionFlags.ShowBody && !(node is TypeDeclaration)) { IProperty property = symbol as IProperty; if (property != null) { writer.Space(); writer.WriteToken(Roles.LBrace, "{"); writer.Space(); if (property.CanGet) { writer.WriteKeyword(PropertyDeclaration.GetKeywordRole, "get"); writer.WriteToken(Roles.Semicolon, ";"); writer.Space(); } if (property.CanSet) { writer.WriteKeyword(PropertyDeclaration.SetKeywordRole, "set"); writer.WriteToken(Roles.Semicolon, ";"); writer.Space(); } writer.WriteToken(Roles.RBrace, "}"); } else { writer.WriteToken(Roles.Semicolon, ";"); } } }
static bool HasNoIdentifier(AstNode node) { return node.GetChildByRole(Roles.Identifier) == Roles.Identifier.NullObject && node.GetChildByRole(Roles.Parameter) == Roles.Parameter.NullObject && node.GetChildByRole(Roles.Argument) == Roles.Argument.NullObject && node.GetChildByRole(Roles.Type) == Roles.Type.NullObject && node.GetChildByRole(Roles.TargetExpression) == Roles.TargetExpression.NullObject && node.GetChildByRole(Roles.TypeParameter) == Roles.TypeParameter.NullObject && node.GetChildByRole(Roles.TypeArgument) == Roles.TypeArgument.NullObject && node.GetChildByRole(Roles.Constraint) == Roles.Constraint.NullObject; }
static AstNode GetFunctionToken(AstNode currentFunction) { return((AstNode)currentFunction.GetChildByRole(Roles.Identifier) ?? currentFunction.GetChildByRole(LambdaExpression.ArrowRole) ?? currentFunction.GetChildByRole(AnonymousMethodExpression.DelegateKeywordRole)); }
public static ResolveResult Resolve(ICompilation compilation, CppParsedFile parsedFile, CompilationUnit cu, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = cu.GetNodeAt(location); if (node == null) { return(null); } if (CppAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer) { // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else { return(null); } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return(null); } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(AstNode.Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return(null); } } if (node == null) { return(null); } if (node.Parent is ObjectCreateExpression && node.Role == ObjectCreateExpression.Roles.Type) { node = node.Parent; } InvocationExpression parentInvocation = null; if (node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } CppAstResolver resolver = new CppAstResolver(compilation, cu, parsedFile); ResolveResult rr = resolver.Resolve(node, cancellationToken); if (rr is MethodGroupResolveResult && parentInvocation != null) { return(resolver.Resolve(parentInvocation)); } else { return(rr); } }
public static ResolveResult Resolve(Lazy<ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = syntaxTree.GetNodeAt(location); if (node == null || node is ArrayInitializerExpression) return null; if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole) { var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); return r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken); } if (CSharpAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer || node.Role == IndexerDeclaration.ThisKeywordRole) { // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else if (node.Parent is BinaryOperatorExpression || node.Parent is UnaryOperatorExpression) { // Resolve user-defined operator node = node.Parent; } else { return null; } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return null; } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return null; } } if (node == null) return null; if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) { node = node.Parent; } else if (node is ThisReferenceExpression && node.Parent is IndexerExpression) { node = node.Parent; } InvocationExpression parentInvocation = null; if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused CSharpAstResolver resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); ResolveResult rr = resolver.Resolve(node, cancellationToken); MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; if (mgrr != null) { // For method groups, resolve the parent invocation instead. if (parentInvocation != null) return resolver.Resolve(parentInvocation); if (node is Expression) { // If it's not an invocation, try if it's a conversion to a delegate type: Conversion c = resolver.GetConversion((Expression)node, cancellationToken); if (c.IsMethodGroupConversion) return new MemberResolveResult(mgrr.TargetResult, c.Method); } } return rr; }
public static ResolveResult Resolve(Lazy <ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = syntaxTree.GetNodeAt(location); if (node == null || node is ArrayInitializerExpression) { return(null); } if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole) { var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); return(r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken)); } if (CSharpAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer || node.Role == IndexerDeclaration.ThisKeywordRole) { // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else if (node.Parent is BinaryOperatorExpression || node.Parent is UnaryOperatorExpression) { // Resolve user-defined operator node = node.Parent; } else { return(null); } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return(null); } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return(null); } } if (node == null) { return(null); } if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) { node = node.Parent; } InvocationExpression parentInvocation = null; if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused CSharpAstResolver resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); ResolveResult rr = resolver.Resolve(node, cancellationToken); MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; if (mgrr != null) { // For method groups, resolve the parent invocation instead. if (parentInvocation != null) { return(resolver.Resolve(parentInvocation)); } if (node is Expression) { // If it's not an invocation, try if it's a conversion to a delegate type: Conversion c = resolver.GetConversion((Expression)node, cancellationToken); if (c.IsMethodGroupConversion) { return(new MemberResolveResult(mgrr.TargetResult, c.Method)); } } } return(rr); }
void AddIssueFor(AstNode currentFunction) { if (IsAsync(currentFunction)) { return; } //Only suggest modifying functions that return void, Task or Task<T>. IType returnType = GetReturnType(ctx, currentFunction); if (returnType == null) { return; } bool isVoid = false; IType resultType = null; switch (returnType.FullName) { case "System.Void": isVoid = true; break; case "System.Threading.Tasks.Task": resultType = returnType.IsParameterized ? returnType.TypeArguments.FirstOrDefault() : null; break; default: return; } var functionBody = currentFunction.GetChildByRole(Roles.Body); var statements = GetStatements(functionBody).ToList(); var returnStatements = statements.OfType <ReturnStatement>().ToList(); var invocations = new List <InvocationExpression>(); var nextInChain = new Dictionary <InvocationExpression, InvocationExpression>(); foreach (var invocation in currentFunction.Descendants.OfType <InvocationExpression>()) { if (invocation.Arguments.Count != 1) { continue; } var lambdaOrDelegate = invocation.Arguments.Single(); Statement lambdaBody; if (lambdaOrDelegate is LambdaExpression) { lambdaBody = lambdaOrDelegate.GetChildByRole(LambdaExpression.BodyRole) as BlockStatement; if (lambdaBody == null) { continue; } } else if (lambdaOrDelegate is AnonymousMethodExpression) { lambdaBody = lambdaOrDelegate.GetChildByRole(Roles.Body); } else { continue; } var resolveResult = ctx.Resolve(invocation) as MemberResolveResult; if (resolveResult == null) { continue; } if (resolveResult.Member.FullName != "System.Threading.Tasks.Task.ContinueWith") { continue; } var parentExpression = invocation.Parent as Expression; if (parentExpression != null) { var mreParent = parentExpression as MemberReferenceExpression; if (mreParent == null || mreParent.MemberName != "ContinueWith") { continue; } var parentInvocation = mreParent.Parent as InvocationExpression; if (parentInvocation == null || parentInvocation.Arguments.Count != 1) { continue; } nextInChain[invocation] = parentInvocation; } invocations.Add(invocation); } if (isVoid && invocations.Count == 0) { //Prevent functions like void Foo() {} from being accepted return; } string taskCompletionSourceIdentifier = null; InvocationExpression returnedContinuation = null; if (isVoid) { if (returnStatements.Any()) { return; } } else if (!isVoid) { if (returnStatements.Count() != 1) { return; } var returnStatement = returnStatements.Single(); if (functionBody.Statements.Last() != returnStatement) { return; } var match = ReturnTaskCompletionSourcePattern.Match(returnStatement); if (match.Success) { var taskCompletionSource = match.Get <IdentifierExpression>("target").Single(); var taskCompletionSourceResolveResult = ctx.Resolve(taskCompletionSource); //Make sure the TaskCompletionSource is a local variable if (!(taskCompletionSourceResolveResult is LocalResolveResult) || taskCompletionSourceResolveResult.Type.FullName != "System.Threading.Tasks.TaskCompletionSource") { return; } taskCompletionSourceIdentifier = taskCompletionSource.Identifier; var cfgBuilder = new ControlFlowGraphBuilder(); var cachedControlFlowGraphs = new Dictionary <BlockStatement, IList <ControlFlowNode> >(); //Make sure there are no unsupported uses of the task completion source foreach (var identifier in functionBody.Descendants.OfType <Identifier>()) { if (identifier.Name != taskCompletionSourceIdentifier) { continue; } var statement = identifier.GetParent <Statement>(); var variableStatement = statement as VariableDeclarationStatement; if (variableStatement != null) { if (functionBody.Statements.First() != variableStatement || variableStatement.Variables.Count != 1) { //This may actually be valid, but it would add even more complexity to this action return; } var initializer = variableStatement.Variables.First().Initializer as ObjectCreateExpression; if (initializer == null || initializer.Arguments.Count != 0 || !initializer.Initializer.IsNull) { return; } var constructedType = ctx.ResolveType(initializer.Type); if (constructedType.FullName != "System.Threading.Tasks.TaskCompletionSource") { return; } continue; } if (statement == returnStatement) { continue; } if (identifier.Parent is MemberReferenceExpression) { //Right side of the member. //We don't care about this case since it's not a reference to the variable. continue; } //The method's taskCompletionSource can only be used on the left side of a member //reference expression (specifically tcs.SetResult). var identifierExpressionParent = identifier.Parent as IdentifierExpression; if (identifierExpressionParent == null) { return; } var memberReferenceExpression = identifierExpressionParent.Parent as MemberReferenceExpression; if (memberReferenceExpression == null) { return; } if (memberReferenceExpression.MemberName != "SetResult") { //Aside from the final return statement, the only member of task completion source //that can be used is SetResult. //Perhaps future versions could also include SetException and SetCancelled. return; } //We found a SetResult -- we will now find out if it is in a proper context AstNode node = memberReferenceExpression; for (;;) { node = node.Parent; if (node == null) { //Abort since this is unexpected (it should never happen) return; } if (node is MethodDeclaration) { //Ok -- tcs.SetResult is in method declaration break; } if (node is LambdaExpression || node is AnonymousMethodExpression) { //It's time to verify if the lambda is supported var lambdaParent = node.Parent as InvocationExpression; if (lambdaParent == null || !invocations.Contains(lambdaParent)) { return; } break; } } var containingContinueWith = node.Parent as InvocationExpression; if (containingContinueWith != null) { if (nextInChain.ContainsKey(containingContinueWith)) { //Unsupported: ContinueWith has a SetResult //but it's not the last in the chain return; } } var containingFunctionBlock = node is LambdaExpression ? (BlockStatement)node.GetChildByRole(LambdaExpression.BodyRole) : node.GetChildByRole(Roles.Body); //Finally, tcs.SetResult must be at the end of its method IList <ControlFlowNode> nodes; if (!cachedControlFlowGraphs.TryGetValue(containingFunctionBlock, out nodes)) { nodes = cfgBuilder.BuildControlFlowGraph(containingFunctionBlock, ctx.CancellationToken); cachedControlFlowGraphs[containingFunctionBlock] = nodes; } var setResultNode = nodes.FirstOrDefault(candidateNode => candidateNode.PreviousStatement == statement); if (setResultNode != null && HasReachableNonReturnNodes(setResultNode)) { //The only allowed outgoing nodes are return statements return; } } } else { //Not TaskCompletionSource-based //Perhaps it is return Task.ContinueWith(foo); if (!invocations.Any()) { return; } var outerMostInvocations = new List <InvocationExpression>(); InvocationExpression currentInvocation = invocations.First(); do { outerMostInvocations.Add(currentInvocation); } while (nextInChain.TryGetValue(currentInvocation, out currentInvocation)); var lastInvocation = outerMostInvocations.Last(); if (returnStatement.Expression != lastInvocation) { return; } //Found return <1>.ContinueWith(<2>); returnedContinuation = lastInvocation; } } //We do not support "return expr" in continuations //The only exception is when the outer method returns that continuation. invocations.RemoveAll(invocation => invocation != returnedContinuation && invocation.Arguments.First().Children.OfType <Statement>().First().DescendantNodesAndSelf(node => node is Statement).OfType <ReturnStatement>().Any(returnStatement => !returnStatement.Expression.IsNull)); AddIssue(new CodeIssue(GetFunctionToken(currentFunction), ctx.TranslateString("Function can be converted to C# 5-style async function"), ctx.TranslateString("Convert to C# 5-style async function"), script => { AddOriginalNodeAnnotations(currentFunction); var newFunction = currentFunction.Clone(); RemoveOriginalNodeAnnotations(currentFunction); //Set async var lambda = newFunction as LambdaExpression; if (lambda != null) { lambda.IsAsync = true; } var anonymousMethod = newFunction as AnonymousMethodExpression; if (anonymousMethod != null) { anonymousMethod.IsAsync = true; } var methodDeclaration = newFunction as MethodDeclaration; if (methodDeclaration != null) { methodDeclaration.Modifiers |= Modifiers.Async; } TransformBody(invocations, isVoid, resultType != null, returnedContinuation, taskCompletionSourceIdentifier, newFunction.GetChildByRole(Roles.Body)); script.Replace(currentFunction, newFunction); })); }
public void FindIfElseInWebMethod(AstNode invocation, CSharpFile file) { if (invocation.GetType().Name == "IfElseStatement" && FindWebMethod(invocation.GetParent <MethodDeclaration>())) { Expression childOfTypeRoleCondition = invocation.GetChildByRole(Roles.Condition); if (childOfTypeRoleCondition.GetType().Name == "UnaryOperatorExpression") { string strToCheck = "Valid" + invocation.GetParent <MethodDeclaration>().Name; if (allPatterns.IfElseValidMethodUnary(strToCheck).Match(childOfTypeRoleCondition).Success) { file.IndexOfIfElStmt.Add((IfElseStatement)invocation); } else if (allPatterns.IfElseValidMethodUnaryOld().Match(childOfTypeRoleCondition).Success) { string strToCheckforAlreadyDeclared = childOfTypeRoleCondition.Descendants.OfType <IdentifierExpression>().First().GetText(); if (strToCheckforAlreadyDeclared.IndexOf(("valid"), StringComparison.OrdinalIgnoreCase) > 0) { file.IndexOfIfElStmtValidation.Add((IfElseStatement)invocation); } } else if (allPatterns.IfElseValidMethodUnaryMemberRef().Match(childOfTypeRoleCondition).Success) { string strToCheckAlreadyDecare = childOfTypeRoleCondition.Descendants.OfType <MemberReferenceExpression>().First().LastChild.GetText(); if (strToCheckAlreadyDecare.IndexOf(("valid"), StringComparison.OrdinalIgnoreCase) > 0) { file.IndexOfIfElStmtValidation.Add((IfElseStatement)invocation); } } } else if (childOfTypeRoleCondition.GetType().Name == "BinaryOperatorExpression") { if (allPatterns.IfElseValidMethodBinary().Match(childOfTypeRoleCondition).Success) { string strToCheck = childOfTypeRoleCondition.Descendants.OfType <IdentifierExpression>().First().GetText(); if (strToCheck.IndexOf("Valid", StringComparison.OrdinalIgnoreCase) > 0) { file.IndexOfIfElStmtValidation.Add((IfElseStatement)invocation); } } else if (allPatterns.IfElseValidMethodBinaryMemberRef().Match(childOfTypeRoleCondition).Success) { string strToCheck = childOfTypeRoleCondition.Descendants.OfType <IdentifierExpression>().First().NextSibling.GetText(); if (strToCheck.IndexOf("Valid", StringComparison.OrdinalIgnoreCase) > 0) { file.IndexOfIfElStmtValidation.Add((IfElseStatement)invocation); } } } //else if () // if(childRole == "UnaryOperatorExpression" || childRole == "BinaryOperatorExpression") // file.IndexOfIfElStmt.Add((IfElseStatement)invocation); /* file.IndexOfIfElStmt.Add((IfElseStatement)invocation); * string strToCheck = null; * try{ * //strToCheck = invocation.FirstChild.NextSibling.NextSibling.FirstChild.NextSibling.FirstChild.GetText(); * strToCheck = invocation.GetChildByRole(Roles.Condition).DescendantsAndSelf.OfType<InvocationExpression>().First().Children.OfType<IdentifierExpression>().First().GetText(); * } * catch(Exception) {} * if (strToCheck != null) * { * if (strToCheck.IndexOf("Valid", StringComparison.OrdinalIgnoreCase) >= 0 && * FoundWebMethodAttribute(invocation.GetParent<MethodDeclaration>())) * { * if (strToCheck == "Valid" + invocation.GetParent<MethodDeclaration>().Name) * { * file.IndexOfIfElStmt.Add((IfElseStatement)invocation); * } * else * { * invocation.Descendants.OfType<InvocationExpression>().First().GetNodeAt(invocation.StartLocation, null); * //foreach(var expr) * } * // else if() * } * } */ } }