private ExpressionSyntax SimplifyInvocation(InvocationExpressionSyntax invocation) { var expression = invocation.Expression; var memberAccess = expression as MemberAccessExpressionSyntax; if (memberAccess != null) { var symbolMap = SemanticMap.From(_document.SemanticModel, memberAccess.Expression, _cancellationToken); var anySideEffects = symbolMap.AllReferencedSymbols.Any(s => s.Kind == SymbolKind.Method || s.Kind == SymbolKind.Property); if (anySideEffects) { var annotation = WarningAnnotation.Create("Warning: Expression may have side effects. Code meaning may change."); expression = expression.ReplaceNode(memberAccess.Expression, memberAccess.Expression.WithAdditionalAnnotations(annotation)); } } return(expression.Parenthesize() .WithAdditionalAnnotations(Formatter.Annotation)); }
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { node = (MemberAccessExpressionSyntax)(base.VisitMemberAccessExpression(node) ?? throw ExceptionUtilities.Unreachable); if (_extensionMethods.Contains(node.Name.Identifier.Text)) { // If an extension method is used as a delegate rather than invoked directly, // there is no semantically valid transformation that will fully qualify the extension method. // For example `Func<int> f = x.M;` is not the same as Func<int> f = () => Extensions.M(x);` // since one captures x by value, and the other by reference. // // We will not visit this node if the parent node was an InvocationExpression, // since we would have expanded the parent node entirely, rather than visiting it. // Therefore it's possible that this is an extension method being used as a delegate so we warn. node = node.WithAdditionalAnnotations(WarningAnnotation.Create(string.Format( WorkspacesResources.Warning_adding_imports_will_bring_an_extension_method_into_scope_with_the_same_name_as_member_access, node.Name.Identifier.Text))); } return(node); }
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var expressionTypeOpt = semanticModel.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1"); var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var semanticFacts = document.GetLanguageService <ISemanticFactsService>(); var generator = editor.Generator; var root = editor.OriginalRoot; foreach (var diagnostic in diagnostics) { var conditionalExpression = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); var conditionExpression = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var whenPart = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); syntaxFacts.GetPartsOfConditionalExpression( conditionalExpression, out var condition, out var whenTrue, out var whenFalse); editor.ReplaceNode(conditionalExpression, (c, g) => { syntaxFacts.GetPartsOfConditionalExpression( c, out var currentCondition, out var currentWhenTrue, out var currentWhenFalse); var coalesceExpression = whenPart == whenTrue ? g.CoalesceExpression(conditionExpression, syntaxFacts.WalkDownParentheses(currentWhenTrue)) : g.CoalesceExpression(conditionExpression, syntaxFacts.WalkDownParentheses(currentWhenFalse)); if (semanticFacts.IsInExpressionTree( semanticModel, conditionalExpression, expressionTypeOpt, cancellationToken)) { coalesceExpression = coalesceExpression.WithAdditionalAnnotations( WarningAnnotation.Create(FeaturesResources.Changes_to_expression_trees_may_result_in_behavior_changes_at_runtime)); } return(coalesceExpression); });
public async Task <Document> MoveDeclarationNearReferenceAsync( Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken) { var state = await ComputeStateAsync(document, localDeclarationStatement, cancellationToken); if (state == null) { return(document); } var root = await document.GetSyntaxRootAsync(cancellationToken); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var crossesMeaningfulBlock = CrossesMeaningfulBlock(state); var warningAnnotation = crossesMeaningfulBlock ? WarningAnnotation.Create(FeaturesResources.Warning_colon_Declaration_changes_scope_and_may_change_meaning) : null; editor.RemoveNode(state.DeclarationStatement); var canMergeDeclarationAndAssignment = await CanMergeDeclarationAndAssignmentAsync(document, state, cancellationToken).ConfigureAwait(false); if (canMergeDeclarationAndAssignment) { MergeDeclarationAndAssignment( document, state, editor, warningAnnotation); } else { await MoveDeclarationToFirstReferenceAsync( document, state, editor, warningAnnotation, cancellationToken).ConfigureAwait(false); } var newRoot = editor.GetChangedRoot(); return(document.WithSyntaxRoot(newRoot)); }
private static async Task <Document> GetTransformedDocumentAsync( Document document, CompilationUnitSyntax compilationUnit, IEnumerable <UsingDirectiveSyntax> allUsingDirectives, AddImportPlacement placement, SimplifierOptions simplifierOptions, CancellationToken cancellationToken) { var bannerService = document.GetRequiredLanguageService <IFileBannerFactsService>(); // Expand usings so that they can be properly simplified after they are relocated. var compilationUnitWithExpandedUsings = await ExpandUsingDirectivesAsync(document, compilationUnit, allUsingDirectives, cancellationToken).ConfigureAwait(false); // Remove the file header from the compilation unit so that we do not lose it when making changes to usings. var(compilationUnitWithoutHeader, fileHeader) = RemoveFileHeader(compilationUnitWithExpandedUsings, bannerService); // A blanket warning that this codefix may change code so that it does not compile. var warningAnnotation = WarningAnnotation.Create(CSharpAnalyzersResources.Warning_colon_Moving_using_directives_may_change_code_meaning); var newCompilationUnit = placement == AddImportPlacement.InsideNamespace ? MoveUsingsInsideNamespace(compilationUnitWithoutHeader, warningAnnotation) : MoveUsingsOutsideNamespaces(compilationUnitWithoutHeader, warningAnnotation); // Re-attach the header now that using have been moved and LeadingTrivia is no longer being altered. var newCompilationUnitWithHeader = AddFileHeader(newCompilationUnit, fileHeader); var newDocument = document.WithSyntaxRoot(newCompilationUnitWithHeader); // Simplify usings now that they have been moved and are in the proper context. #if CODE_STYLE #pragma warning disable RS0030 // Do not used banned APIs (ReduceAsync with SimplifierOptions isn't public) return(await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, optionSet : null, cancellationToken).ConfigureAwait(false)); #pragma warning restore #else return(await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(false)); #endif }
protected SyntaxAnnotation CreateWarningAnnotation() => WarningAnnotation.Create(FeaturesResources.Warning_colon_semantics_may_change_when_converting_statement);
private static void ApplyEdit( SyntaxEditor editor, SemanticModel semanticModel, INamedTypeSymbol expressionTypeOpt, ISyntaxFactsService syntaxFacts, ISemanticFactsService semanticFacts, Diagnostic diagnostic, CancellationToken cancellationToken ) { var root = editor.OriginalRoot; var conditionalExpression = root.FindNode( diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true ); var conditionalPartHigh = root.FindNode(diagnostic.AdditionalLocations[1].SourceSpan); var whenPart = root.FindNode(diagnostic.AdditionalLocations[2].SourceSpan); syntaxFacts.GetPartsOfConditionalExpression( conditionalExpression, out var condition, out var whenTrue, out var whenFalse ); var conditionalPartLow = syntaxFacts.WalkDownParentheses(conditionalPartHigh); editor.ReplaceNode( conditionalExpression, (c, g) => { syntaxFacts.GetPartsOfConditionalExpression( c, out var currentCondition, out var currentWhenTrue, out var currentWhenFalse ); var coalesceExpression = GetCoalesceExpression( syntaxFacts, g, whenPart, whenTrue, conditionalPartLow, currentWhenTrue, currentWhenFalse ) .WithTrailingTrivia(conditionalExpression.GetTrailingTrivia()); if ( semanticFacts.IsInExpressionTree( semanticModel, conditionalExpression, expressionTypeOpt, cancellationToken ) ) { coalesceExpression = coalesceExpression.WithAdditionalAnnotations( WarningAnnotation.Create( AnalyzersResources.Changes_to_expression_trees_may_result_in_behavior_changes_at_runtime ) ); } return(coalesceExpression.WithAdditionalAnnotations(Formatter.Annotation)); }
public static async Task MakeLocalFunctionStaticAsync( Document document, LocalFunctionStatementSyntax localFunction, ImmutableArray <ISymbol> captures, SyntaxEditor syntaxEditor, CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)) !; var semanticModel = (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false)) !; var localFunctionSymbol = semanticModel.GetDeclaredSymbol(localFunction, cancellationToken); Contract.ThrowIfNull(localFunctionSymbol, "We should have gotten a method symbol for a local function."); var documentImmutableSet = ImmutableHashSet.Create(document); // Finds all the call sites of the local function var referencedSymbols = await SymbolFinder.FindReferencesAsync( localFunctionSymbol, document.Project.Solution, documentImmutableSet, cancellationToken).ConfigureAwait(false); // Now we need to find all the references to the local function that we might need to fix. var shouldWarn = false; using var builderDisposer = ArrayBuilder <InvocationExpressionSyntax> .GetInstance(out var invocations); foreach (var referencedSymbol in referencedSymbols) { foreach (var location in referencedSymbol.Locations) { // We limited the search scope to the single document, // so all reference should be in the same tree. var referenceNode = root.FindNode(location.Location.SourceSpan); if (referenceNode is not IdentifierNameSyntax identifierNode) { // Unexpected scenario, skip and warn. shouldWarn = true; continue; } if (identifierNode.Parent is InvocationExpressionSyntax invocation) { invocations.Add(invocation); } else { // We won't be able to fix non-invocation references, // e.g. creating a delegate. shouldWarn = true; } } } var parameterAndCapturedSymbols = CreateParameterSymbols(captures); // Fix all invocations by passing in additional arguments. foreach (var invocation in invocations) { syntaxEditor.ReplaceNode( invocation, (node, generator) => { var currentInvocation = (InvocationExpressionSyntax)node; var seenNamedArgument = currentInvocation.ArgumentList.Arguments.Any(a => a.NameColon != null); var seenDefaultArgumentValue = currentInvocation.ArgumentList.Arguments.Count < localFunction.ParameterList.Parameters.Count; var newArguments = parameterAndCapturedSymbols.Select( p => (ArgumentSyntax)generator.Argument( seenNamedArgument || seenDefaultArgumentValue ? p.symbol.Name : null, p.symbol.RefKind, p.capture.Name.ToIdentifierName())); var newArgList = currentInvocation.ArgumentList.WithArguments(currentInvocation.ArgumentList.Arguments.AddRange(newArguments)); return(currentInvocation.WithArgumentList(newArgList)); }); } // In case any of the captured variable isn't camel-cased, // we need to change the referenced name inside local function to use the new parameter's name. foreach (var(parameter, capture) in parameterAndCapturedSymbols) { if (parameter.Name == capture.Name) { continue; } var referencedCaptureSymbols = await SymbolFinder.FindReferencesAsync( capture, document.Project.Solution, documentImmutableSet, cancellationToken).ConfigureAwait(false); foreach (var referencedSymbol in referencedCaptureSymbols) { foreach (var location in referencedSymbol.Locations) { var referenceSpan = location.Location.SourceSpan; if (!localFunction.FullSpan.Contains(referenceSpan)) { continue; } var referenceNode = root.FindNode(referenceSpan); if (referenceNode is IdentifierNameSyntax identifierNode) { syntaxEditor.ReplaceNode( identifierNode, (node, generator) => generator.IdentifierName(parameter.Name.ToIdentifierToken()).WithTriviaFrom(node)); } } } } var codeGenerator = document.GetRequiredLanguageService <ICodeGenerationService>(); var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var info = options.GetInfo(CodeGenerationContext.Default, document.Project); // Updates the local function declaration with variables passed in as parameters syntaxEditor.ReplaceNode( localFunction, (node, generator) => { var localFunctionWithNewParameters = codeGenerator.AddParameters( node, parameterAndCapturedSymbols.SelectAsArray(p => p.symbol), info, cancellationToken); if (shouldWarn) { var annotation = WarningAnnotation.Create(CSharpCodeFixesResources.Warning_colon_Adding_parameters_to_local_function_declaration_may_produce_invalid_code); localFunctionWithNewParameters = localFunctionWithNewParameters.WithAdditionalAnnotations(annotation); } return(AddStaticModifier(localFunctionWithNewParameters, CSharpSyntaxGenerator.Instance)); }); }
private async Task <Document> ConvertToGeneratedDllImport( Document doc, MethodDeclarationSyntax methodSyntax, IMethodSymbol methodSymbol, AttributeData dllImportAttr, INamedTypeSymbol generatedDllImportAttrType, bool usePreprocessorDefines, CancellationToken cancellationToken) { DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; var dllImportSyntax = (AttributeSyntax)dllImportAttr !.ApplicationSyntaxReference !.GetSyntax(cancellationToken); // Create GeneratedDllImport attribute based on the DllImport attribute SyntaxNode generatedDllImportSyntax = GetGeneratedDllImportAttribute( editor, generator, dllImportSyntax, methodSymbol.GetDllImportData() !, generatedDllImportAttrType, out SyntaxNode? unmanagedCallConvAttributeMaybe); // Add annotation about potential behavioural and compatibility changes generatedDllImportSyntax = generatedDllImportSyntax.WithAdditionalAnnotations( WarningAnnotation.Create(string.Format(Resources.ConvertToGeneratedDllImportWarning, "[TODO] Documentation link"))); // Replace DllImport with GeneratedDllImport SyntaxNode generatedDeclaration = generator.ReplaceNode(methodSyntax, dllImportSyntax, generatedDllImportSyntax); if (unmanagedCallConvAttributeMaybe is not null) { generatedDeclaration = generator.AddAttributes(generatedDeclaration, unmanagedCallConvAttributeMaybe); } // Replace extern keyword with partial keyword generatedDeclaration = generator.WithModifiers( generatedDeclaration, generator.GetModifiers(methodSyntax) .WithIsExtern(false) .WithPartial(true)); if (!usePreprocessorDefines) { // Replace the original method with the updated one editor.ReplaceNode(methodSyntax, generatedDeclaration); } else { // #if DLLIMPORTGENERATOR_ENABLED generatedDeclaration = generatedDeclaration.WithLeadingTrivia( generatedDeclaration.GetLeadingTrivia() .AddRange(new[] { SyntaxFactory.Trivia(SyntaxFactory.IfDirectiveTrivia(SyntaxFactory.IdentifierName("DLLIMPORTGENERATOR_ENABLED"), isActive: true, branchTaken: true, conditionValue: true)), SyntaxFactory.ElasticMarker })); // #else generatedDeclaration = generatedDeclaration.WithTrailingTrivia( generatedDeclaration.GetTrailingTrivia() .AddRange(new[] { SyntaxFactory.Trivia(SyntaxFactory.ElseDirectiveTrivia(isActive: false, branchTaken: false)), SyntaxFactory.ElasticMarker })); // Remove existing leading trivia - it will be on the GeneratedDllImport method MethodDeclarationSyntax updatedDeclaration = methodSyntax.WithLeadingTrivia(); // #endif updatedDeclaration = updatedDeclaration.WithTrailingTrivia( methodSyntax.GetTrailingTrivia() .AddRange(new[] { SyntaxFactory.Trivia(SyntaxFactory.EndIfDirectiveTrivia(isActive: true)), SyntaxFactory.ElasticMarker })); // Add the GeneratedDllImport method editor.InsertBefore(methodSyntax, generatedDeclaration); // Replace the original method with the updated DllImport method editor.ReplaceNode(methodSyntax, updatedDeclaration); } return(editor.GetChangedDocument()); }
private static async Task <Document> InlineTemporaryAsync(Document document, VariableDeclaratorSyntax declarator, CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; // Annotate the variable declarator so that we can get back to it later. var updatedDocument = await document.ReplaceNodeAsync(declarator, declarator.WithAdditionalAnnotations(DefinitionAnnotation), cancellationToken).ConfigureAwait(false); var semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); // Create the expression that we're actually going to inline. var expressionToInline = await CreateExpressionToInlineAsync(variableDeclarator, updatedDocument, cancellationToken).ConfigureAwait(false); // Collect the identifier names for each reference. var local = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken); var symbolRefs = await SymbolFinder.FindReferencesAsync(local, updatedDocument.Project.Solution, cancellationToken).ConfigureAwait(false); var referencedSymbol = symbolRefs.SingleOrDefault(r => Equals(r.Definition, local)); var references = referencedSymbol == null?SpecializedCollections.EmptyEnumerable <ReferenceLocation>() : referencedSymbol.Locations; var syntaxRoot = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Collect the topmost parenting expression for each reference. var nonConflictingIdentifierNodes = references .Select(loc => (IdentifierNameSyntax)syntaxRoot.FindToken(loc.Location.SourceSpan.Start).Parent) .Where(ident => !HasConflict(ident, variableDeclarator)); // Add referenceAnnotations to identifier nodes being replaced. updatedDocument = await updatedDocument.ReplaceNodesAsync( nonConflictingIdentifierNodes, (o, n) => n.WithAdditionalAnnotations(ReferenceAnnotation), cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); // Get the annotated reference nodes. nonConflictingIdentifierNodes = await FindReferenceAnnotatedNodesAsync(updatedDocument, cancellationToken).ConfigureAwait(false); var topmostParentingExpressions = nonConflictingIdentifierNodes .Select(ident => GetTopMostParentingExpression(ident)) .Distinct().ToList(); var originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.Initializer.Value, cancellationToken); // Checks to see if inlining the temporary variable may change the code's meaning. This can only apply if the variable has two or more // references. We later use this heuristic to determine whether or not to display a warning message to the user. var mayContainSideEffects = references.Count() > 1 && MayContainSideEffects(variableDeclarator.Initializer.Value); // Make each topmost parenting statement or Equals Clause Expressions semantically explicit. updatedDocument = await updatedDocument.ReplaceNodesAsync(topmostParentingExpressions, (o, n) => { var node = Simplifier.Expand(n, semanticModel, workspace, cancellationToken: cancellationToken); // warn when inlining into a conditional expression, as the inlined expression will not be executed. if (semanticModel.GetSymbolInfo(o).Symbol is IMethodSymbol { IsConditional : true }) { node = node.WithAdditionalAnnotations( WarningAnnotation.Create(CSharpFeaturesResources.Warning_Inlining_temporary_into_conditional_method_call)); } // If the refactoring may potentially change the code's semantics, display a warning message to the user. if (mayContainSideEffects) { node = node.WithAdditionalAnnotations( WarningAnnotation.Create(CSharpFeaturesResources.Warning_Inlining_temporary_variable_may_change_code_meaning)); } return(node); }, cancellationToken).ConfigureAwait(false);
protected override async Task <Document?> FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray <Diagnostic> diagnostics) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; SyntaxNode?root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); if (root == null) { return(document); } foreach (Diagnostic diagnostic in diagnostics) { // Get the syntax node tied to the diagnostic and check that it is a method declaration if (root.FindNode(diagnostic.Location.SourceSpan) is not MethodDeclarationSyntax methodSyntax) { continue; } if (editor.SemanticModel.GetDeclaredSymbol(methodSyntax, fixAllContext.CancellationToken) is not IMethodSymbol methodSymbol) { continue; } SyntaxNode generatedDeclaration = await ConvertMethodDeclarationToLibraryImport(methodSyntax, editor, generator, methodSymbol, GetSuffixFromEquivalenceKey(fixAllContext.CodeActionEquivalenceKey), fixAllContext.CancellationToken).ConfigureAwait(false); if (!methodSymbol.MethodImplementationFlags.HasFlag(System.Reflection.MethodImplAttributes.PreserveSig)) { bool shouldWarn = await TransformCallersOfNoPreserveSigMethod(editor, methodSymbol, fixAllContext.CancellationToken).ConfigureAwait(false); if (shouldWarn) { generatedDeclaration = generatedDeclaration.WithAdditionalAnnotations(WarningAnnotation.Create(SR.ConvertNoPreserveSigDllImportToGeneratedMayProduceInvalidCode)); } } // Replace the original method with the updated one editor.ReplaceNode(methodSyntax, generatedDeclaration); MakeEnclosingTypesPartial(editor, methodSyntax); } return(editor.GetChangedDocument()); }
private async Task <Document> ConvertToLibraryImport( Document doc, MethodDeclarationSyntax methodSyntax, IMethodSymbol methodSymbol, AttributeData dllImportAttr, INamedTypeSymbol generatedDllImportAttrType, char?entryPointSuffix, CancellationToken cancellationToken) { DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; var dllImportSyntax = (AttributeSyntax)await dllImportAttr !.ApplicationSyntaxReference !.GetSyntaxAsync(cancellationToken).ConfigureAwait(false); // Create GeneratedDllImport attribute based on the DllImport attribute SyntaxNode generatedDllImportSyntax = GetGeneratedDllImportAttribute( editor, generator, dllImportSyntax, methodSymbol, generatedDllImportAttrType, entryPointSuffix, out SyntaxNode? unmanagedCallConvAttributeMaybe); // Add annotation about potential behavioural and compatibility changes generatedDllImportSyntax = generatedDllImportSyntax.WithAdditionalAnnotations( WarningAnnotation.Create(string.Format(Resources.ConvertToLibraryImportWarning, "[TODO] Documentation link"))); // Replace DllImport with GeneratedDllImport SyntaxNode generatedDeclaration = generator.ReplaceNode(methodSyntax, dllImportSyntax, generatedDllImportSyntax); if (!methodSymbol.MethodImplementationFlags.HasFlag(System.Reflection.MethodImplAttributes.PreserveSig)) { generatedDeclaration = await RemoveNoPreserveSigTransform(editor, generatedDeclaration, methodSymbol, cancellationToken).ConfigureAwait(false); } if (unmanagedCallConvAttributeMaybe is not null) { generatedDeclaration = generator.AddAttributes(generatedDeclaration, unmanagedCallConvAttributeMaybe); } // Replace extern keyword with partial keyword generatedDeclaration = generator.WithModifiers( generatedDeclaration, generator.GetModifiers(methodSyntax) .WithIsExtern(false) .WithPartial(true)); foreach (IParameterSymbol parameter in methodSymbol.Parameters) { if (parameter.Type.SpecialType == SpecialType.System_Boolean && !parameter.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) { MethodDeclarationSyntax generatedDeclarationSyntax = (MethodDeclarationSyntax)generatedDeclaration; ParameterSyntax generatedParameterSyntax = generatedDeclarationSyntax.ParameterList.Parameters[parameter.Ordinal]; generatedDeclaration = generator.ReplaceNode(generatedDeclaration, generatedParameterSyntax, generator.AddAttributes(generatedParameterSyntax, GenerateMarshalAsUnmanagedTypeBoolAttribute(generator))); } } if (methodSymbol.ReturnType.SpecialType == SpecialType.System_Boolean && !methodSymbol.GetReturnTypeAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) { generatedDeclaration = generator.AddReturnAttributes(generatedDeclaration, GenerateMarshalAsUnmanagedTypeBoolAttribute(generator)); } // Replace the original method with the updated one editor.ReplaceNode(methodSyntax, generatedDeclaration); return(editor.GetChangedDocument()); }
protected static SyntaxAnnotation CreatePossibleInvalidCodeWarning() { return(WarningAnnotation.Create(MicrosoftNetCoreAnalyzersResources.MakeMethodDeclaredOnImplementationTypeStaticMayProduceInvalidCode)); }
public override async Task <SelectionResult> GetValidSelectionAsync(CancellationToken cancellationToken) { if (!this.ContainsValidSelection) { return(NullSelection); } var text = this.SemanticDocument.Text; var root = this.SemanticDocument.Root; var model = this.SemanticDocument.SemanticModel; var doc = this.SemanticDocument; // go through pipe line and calculate information about the user selection var selectionInfo = GetInitialSelectionInfo(root, text, cancellationToken); selectionInfo = AssignInitialFinalTokens(selectionInfo, root, cancellationToken); selectionInfo = AdjustFinalTokensBasedOnContext(selectionInfo, model, cancellationToken); selectionInfo = AssignFinalSpan(selectionInfo, text, cancellationToken); selectionInfo = ApplySpecialCases(selectionInfo, text, cancellationToken); selectionInfo = CheckErrorCasesAndAppendDescriptions(selectionInfo, root, model, cancellationToken); // there was a fatal error that we couldn't even do negative preview, return error result if (selectionInfo.Status.FailedWithNoBestEffortSuggestion()) { return(new ErrorSelectionResult(selectionInfo.Status)); } var controlFlowSpan = GetControlFlowSpan(selectionInfo); if (!selectionInfo.SelectionInExpression) { var statementRange = GetStatementRangeContainedInSpan <StatementSyntax>(root, controlFlowSpan, cancellationToken); if (statementRange == null) { selectionInfo = selectionInfo.WithStatus(s => s.With(OperationStatusFlag.None, CSharpFeaturesResources.Can_t_determine_valid_range_of_statements_to_extract)); return(new ErrorSelectionResult(selectionInfo.Status)); } var isFinalSpanSemanticallyValid = IsFinalSpanSemanticallyValidSpan(model, controlFlowSpan, statementRange, cancellationToken); if (!isFinalSpanSemanticallyValid) { // check control flow only if we are extracting statement level, not expression // level. you can not have goto that moves control out of scope in expression level // (even in lambda) selectionInfo = selectionInfo.WithStatus(s => s.With(OperationStatusFlag.BestEffort, CSharpFeaturesResources.Not_all_code_paths_return)); } } // Warn if local functions are in selection since data flow analysis // cannot correctly analyze them // https://github.com/dotnet/roslyn/issues/14214 if (SpanInvolvesLocalFunction(selectionInfo.FinalSpan, model, root)) { selectionInfo = selectionInfo.WithStatus(s => s.With( OperationStatusFlag.Succeeded | OperationStatusFlag.BestEffort, CSharpFeaturesResources.Warning_Extracting_a_local_function_reference_may_produce_invalid_code)); var commonRoot = selectionInfo.CommonRootFromOriginalSpan; var annotated = commonRoot.WithAdditionalAnnotations( WarningAnnotation.Create(CSharpFeaturesResources.Warning_Extracting_a_local_function_reference_may_produce_invalid_code)); doc = await doc.WithSyntaxRootAsync( root.ReplaceNode(commonRoot, annotated), cancellationToken).ConfigureAwait(false); selectionInfo.FirstTokenInOriginalSpan = doc.Root.FindToken(selectionInfo.FirstTokenInOriginalSpan.SpanStart); selectionInfo.LastTokenInOriginalSpan = doc.Root.FindToken(selectionInfo.LastTokenInOriginalSpan.SpanStart); selectionInfo.FirstTokenInFinalSpan = doc.Root.FindToken(selectionInfo.FirstTokenInFinalSpan.SpanStart); selectionInfo.LastTokenInFinalSpan = doc.Root.FindToken(selectionInfo.LastTokenInFinalSpan.SpanStart); } return(await CSharpSelectionResult.CreateAsync( selectionInfo.Status, selectionInfo.OriginalSpan, selectionInfo.FinalSpan, this.Options, selectionInfo.SelectionInExpression, doc, selectionInfo.FirstTokenInFinalSpan, selectionInfo.LastTokenInFinalSpan, cancellationToken).ConfigureAwait(false)); }
public async Task <Document> MoveDeclarationNearReferenceAsync( Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken ) { var state = await ComputeStateAsync( document, localDeclarationStatement, cancellationToken ) .ConfigureAwait(false); if (state == null) { return(document); } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var crossesMeaningfulBlock = CrossesMeaningfulBlock(state); var warningAnnotation = crossesMeaningfulBlock ? WarningAnnotation.Create( WorkspaceExtensionsResources.Warning_colon_Declaration_changes_scope_and_may_change_meaning ) : null; var canMergeDeclarationAndAssignment = await CanMergeDeclarationAndAssignmentAsync( document, state, cancellationToken ) .ConfigureAwait(false); if (canMergeDeclarationAndAssignment) { editor.RemoveNode(state.DeclarationStatement); MergeDeclarationAndAssignment(document, state, editor, warningAnnotation); } else { var statementIndex = state.OutermostBlockStatements.IndexOf( state.DeclarationStatement ); if ( statementIndex + 1 < state.OutermostBlockStatements.Count && state.OutermostBlockStatements[statementIndex + 1] == state.FirstStatementAffectedInInnermostBlock ) { // Already at the correct location. return(document); } editor.RemoveNode(state.DeclarationStatement); await MoveDeclarationToFirstReferenceAsync( document, state, editor, warningAnnotation, cancellationToken ) .ConfigureAwait(false); } var newRoot = editor.GetChangedRoot(); return(document.WithSyntaxRoot(newRoot)); }