protected override bool TryInitializeState( SemanticDocument document, SimpleNameSyntax simpleName, CancellationToken cancellationToken, out GenerateTypeServiceStateOptions generateTypeServiceStateOptions) { generateTypeServiceStateOptions = new GenerateTypeServiceStateOptions(); if (simpleName.IsNullWithNoType()) { return(false); } if (SyntaxFacts.IsAliasQualifier(simpleName)) { return(false); } // Never offer if we're in a using directive, unless its a static using. The feeling here is that it's highly // unlikely that this would be a location where a user would be wanting to generate // something. They're really just trying to reference something that exists but // isn't available for some reason (i.e. a missing reference). var usingDirectiveSyntax = simpleName.GetAncestorOrThis <ImportDirectiveSyntax>(); if (usingDirectiveSyntax != null && usingDirectiveSyntax.StaticKeyword.Kind() != SyntaxKind.StaticKeyword) { return(false); } ExpressionSyntax nameOrMemberAccessExpression = null; if (simpleName.IsRightSideOfDot()) { // This simplename comes from the cref if (simpleName.IsParentKind(SyntaxKind.NameMemberCref)) { return(false); } nameOrMemberAccessExpression = generateTypeServiceStateOptions.NameOrMemberAccessExpression = (ExpressionSyntax)simpleName.Parent; // If we're on the right side of a dot, then the left side better be a name (and // not an arbitrary expression). var leftSideExpression = simpleName.GetLeftSideOfDot(); if (!leftSideExpression.IsKind( SyntaxKind.QualifiedName, SyntaxKind.IdentifierName, SyntaxKind.AliasQualifiedName, SyntaxKind.GenericName, SyntaxKind.SimpleMemberAccessExpression)) { return(false); } } else { nameOrMemberAccessExpression = generateTypeServiceStateOptions.NameOrMemberAccessExpression = simpleName; } // BUG(5712): Don't offer generate type in an enum's base list. if (nameOrMemberAccessExpression.Parent is BaseTypeSyntax && nameOrMemberAccessExpression.Parent.IsParentKind(SyntaxKind.ImplementList) && ((BaseTypeSyntax)nameOrMemberAccessExpression.Parent).Type == nameOrMemberAccessExpression && nameOrMemberAccessExpression.Parent.Parent.IsParentKind(SyntaxKind.EnumDeclaration)) { return(false); } // If we can guarantee it's a type only context, great. Otherwise, we may not want to // provide this here. var semanticModel = document.SemanticModel; if (!SyntaxFacts.IsInNamespaceOrTypeContext(nameOrMemberAccessExpression)) { // Don't offer Generate Type in an expression context *unless* we're on the left // side of a dot. In that case the user might be making a type that they're // accessing a static off of. var syntaxTree = semanticModel.SyntaxTree; var start = nameOrMemberAccessExpression.SpanStart; var tokenOnLeftOfStart = syntaxTree.FindTokenOnLeftOfPosition(start, cancellationToken); var isExpressionContext = syntaxTree.IsExpressionContext(start, tokenOnLeftOfStart, attributes: true, cancellationToken: cancellationToken, semanticModelOpt: semanticModel); var isStatementContext = syntaxTree.IsStatementContext(start, tokenOnLeftOfStart, cancellationToken); var isExpressionOrStatementContext = isExpressionContext || isStatementContext; // Delegate Type Creation is not allowed in Non Type Namespace Context generateTypeServiceStateOptions.IsDelegateAllowed = false; if (!isExpressionOrStatementContext) { return(false); } if (!simpleName.IsLeftSideOfDot() && !simpleName.IsInsideNameOfExpression(semanticModel, cancellationToken)) { if (nameOrMemberAccessExpression == null || !nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || !simpleName.IsRightSideOfDot()) { return(false); } var leftSymbol = semanticModel.GetSymbolInfo(((MemberAccessExpressionSyntax)nameOrMemberAccessExpression).Expression, cancellationToken).Symbol; var token = simpleName.GetLastToken().GetNextToken(); // We let only the Namespace to be left of the Dot if (leftSymbol == null || !leftSymbol.IsKind(SymbolKind.Namespace) || !token.IsKind(SyntaxKind.DotToken)) { return(false); } else { generateTypeServiceStateOptions.IsMembersWithModule = true; generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess = true; } } // Global Namespace if (!generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess && !SyntaxFacts.IsInNamespaceOrTypeContext(simpleName)) { var token = simpleName.GetLastToken().GetNextToken(); if (token.IsKind(SyntaxKind.DotToken) && simpleName.Parent == token.Parent) { generateTypeServiceStateOptions.IsMembersWithModule = true; generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess = true; } } } var fieldDeclaration = simpleName.GetAncestor <FieldDeclarationSyntax>(); if (fieldDeclaration != null && fieldDeclaration.Parent is CompilationUnitSyntax && document.Document.SourceCodeKind == SourceCodeKind.Regular) { return(false); } // Check to see if Module could be an option in the Type Generation in Cross Language Generation var nextToken = simpleName.GetLastToken().GetNextToken(); if (simpleName.IsLeftSideOfDot() || nextToken.IsKind(SyntaxKind.DotToken)) { if (simpleName.IsRightSideOfDot()) { if (simpleName.Parent is QualifiedNameSyntax parent) { var leftSymbol = semanticModel.GetSymbolInfo(parent.Left, cancellationToken).Symbol; if (leftSymbol != null && leftSymbol.IsKind(SymbolKind.Namespace)) { generateTypeServiceStateOptions.IsMembersWithModule = true; } } } } if (SyntaxFacts.IsInNamespaceOrTypeContext(nameOrMemberAccessExpression)) { if (nextToken.IsKind(SyntaxKind.DotToken)) { // In Namespace or Type Context we cannot have Interface, Enum, Delegate as part of the Left Expression of a QualifiedName generateTypeServiceStateOptions.IsDelegateAllowed = false; generateTypeServiceStateOptions.IsInterfaceOrEnumNotAllowedInTypeContext = true; generateTypeServiceStateOptions.IsMembersWithModule = true; } // case: class Goo<T> where T: MyType if (nameOrMemberAccessExpression.GetAncestors <TypeConstraintSyntax>().Any()) { generateTypeServiceStateOptions.IsClassInterfaceTypes = true; return(true); } // Events if (nameOrMemberAccessExpression.GetAncestors <EventFieldDeclarationSyntax>().Any() || nameOrMemberAccessExpression.GetAncestors <EventDeclarationSyntax>().Any()) { // Case : event goo name11 // Only Delegate if (simpleName.Parent != null && !(simpleName.Parent is QualifiedNameSyntax)) { generateTypeServiceStateOptions.IsDelegateOnly = true; return(true); } // Case : event SomeSymbol.goo name11 if (nameOrMemberAccessExpression is QualifiedNameSyntax) { // Only Namespace, Class, Struct and Module are allowed to contain Delegate // Case : event Something.Mytype.<Delegate> Identifier if (nextToken.IsKind(SyntaxKind.DotToken)) { if (nameOrMemberAccessExpression.Parent != null && nameOrMemberAccessExpression.Parent is QualifiedNameSyntax) { return(true); } else { Contract.Fail("Cannot reach this point"); } } else { // Case : event Something.<Delegate> Identifier generateTypeServiceStateOptions.IsDelegateOnly = true; return(true); } } } } else { // MemberAccessExpression if ((nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || (nameOrMemberAccessExpression.Parent != null && nameOrMemberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))) && nameOrMemberAccessExpression.IsLeftSideOfDot()) { // Check to see if the expression is part of Invocation Expression ExpressionSyntax outerMostMemberAccessExpression = null; if (nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { outerMostMemberAccessExpression = nameOrMemberAccessExpression; } else { Debug.Assert(nameOrMemberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)); outerMostMemberAccessExpression = (ExpressionSyntax)nameOrMemberAccessExpression.Parent; } outerMostMemberAccessExpression = outerMostMemberAccessExpression.GetAncestorsOrThis <ExpressionSyntax>().SkipWhile(n => n != null && n.IsKind(SyntaxKind.SimpleMemberAccessExpression)).FirstOrDefault(); if (outerMostMemberAccessExpression != null && outerMostMemberAccessExpression is InvocationExpressionSyntax) { generateTypeServiceStateOptions.IsEnumNotAllowed = true; } } } // Cases: // // 1 - Function Address // var s2 = new MyD2(goo); // // 2 - Delegate // MyD1 d = null; // var s1 = new MyD2(d); // // 3 - Action // Action action1 = null; // var s3 = new MyD2(action1); // // 4 - Func // Func<int> lambda = () => { return 0; }; // var s4 = new MyD3(lambda); if (nameOrMemberAccessExpression.Parent is ObjectCreationExpressionSyntax) { var objectCreationExpressionOpt = generateTypeServiceStateOptions.ObjectCreationExpressionOpt = (ObjectCreationExpressionSyntax)nameOrMemberAccessExpression.Parent; // Enum and Interface not Allowed in Object Creation Expression generateTypeServiceStateOptions.IsInterfaceOrEnumNotAllowedInTypeContext = true; if (objectCreationExpressionOpt.ArgumentList != null) { if (objectCreationExpressionOpt.ArgumentList.CloseParenToken.IsMissing) { return(false); } // Get the Method symbol for the Delegate to be created if (generateTypeServiceStateOptions.IsDelegateAllowed && objectCreationExpressionOpt.ArgumentList.Arguments.Count == 1 && objectCreationExpressionOpt.ArgumentList.Arguments[0].Expression.Kind() != SyntaxKind.DeclarationExpression) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, objectCreationExpressionOpt.ArgumentList.Arguments[0].Expression, cancellationToken); } else { generateTypeServiceStateOptions.IsDelegateAllowed = false; } } if (objectCreationExpressionOpt.Initializer != null) { foreach (var expression in objectCreationExpressionOpt.Initializer.Expressions) { var simpleAssignmentExpression = expression as AssignmentExpressionSyntax; if (simpleAssignmentExpression == null) { continue; } var name = simpleAssignmentExpression.Left as SimpleNameSyntax; if (name == null) { continue; } generateTypeServiceStateOptions.PropertiesToGenerate.Add(name); } } } if (generateTypeServiceStateOptions.IsDelegateAllowed) { // MyD1 z1 = goo; if (nameOrMemberAccessExpression.Parent.IsKind(SyntaxKind.VariableDeclaration)) { var variableDeclaration = (VariableDeclarationSyntax)nameOrMemberAccessExpression.Parent; var firstVarDeclWithInitializer = variableDeclaration.Initializer != null && variableDeclaration.Initializer.Value != null ? variableDeclaration : null; if (firstVarDeclWithInitializer != null && firstVarDeclWithInitializer.Initializer != null && firstVarDeclWithInitializer.Initializer.Value != null) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, firstVarDeclWithInitializer.Initializer.Value, cancellationToken); } } // var w1 = (MyD1)goo; if (nameOrMemberAccessExpression.Parent.IsKind(SyntaxKind.CastExpression)) { var castExpression = (CastExpressionSyntax)nameOrMemberAccessExpression.Parent; if (castExpression.Expression != null) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, castExpression.Expression, cancellationToken); } } } return(true); }
protected abstract bool TryInitializeState(SemanticDocument document, TSimpleNameSyntax simpleName, CancellationToken cancellationToken, out GenerateTypeServiceStateOptions generateTypeServiceStateOptions);