static bool IsDeclarationConstFriendly(LocalDeclarationStatementSyntax declaration, SemanticModel semanticModel) { // all variables could be const? foreach (var variable in declaration.Declaration.Variables) { if (variable.Initializer == null) return false; if (variable.Initializer.Value is InterpolatedStringExpressionSyntax) return false; // is constant var constantValue = semanticModel.GetConstantValue(variable.Initializer.Value); var valueIsConstant = constantValue.HasValue; if (!valueIsConstant) return false; // if reference type, value is null? var variableTypeName = declaration.Declaration.Type; var variableType = semanticModel.GetTypeInfo(variableTypeName).ConvertedType; if (variableType.IsReferenceType && variableType.SpecialType != SpecialType.System_String && constantValue.Value != null) return false; // nullable? if (variableType.OriginalDefinition?.SpecialType == SpecialType.System_Nullable_T) return false; // value can be converted to variable type? var conversion = semanticModel.ClassifyConversion(variable.Initializer.Value, variableType); if (!conversion.Exists || conversion.IsUserDefined) return false; } return true; }
private static bool AllTypesAreConvertible(SemanticModel semanticModel, ArrayCreationExpressionSyntax arrayCreation, IArrayTypeSymbol arrayType) { return arrayCreation.Initializer.Initializers.All(initializer => { var conversion = semanticModel.ClassifyConversion(initializer, arrayType.ElementType); return conversion.Exists && (conversion.IsIdentity || conversion.IsWidening); }); }
private static bool ArgumentsMatchParameters(ArgumentListSyntax argumentList, List<INamedTypeSymbol> argumentTypes, IMethodSymbol possibleOtherMethod, SemanticModel semanticModel) { var matchedParameters = new List<IParameterSymbol>(); for (int i = 0; i < argumentList.Arguments.Count; i++) { var argument = argumentList.Arguments[i]; var argumentType = argumentTypes[i]; IParameterSymbol parameter; if (!MethodParameterLookup.TryGetParameterSymbol(argument, argumentList, possibleOtherMethod, out parameter)) { return false; } if (argumentType == null) { if (!parameter.Type.IsReferenceType) { return false; } } else { var conversion = semanticModel.ClassifyConversion(argument.Expression, parameter.Type); if (!conversion.IsImplicit) { return false; } } matchedParameters.Add(parameter); } var nonMatchedParameters = possibleOtherMethod.Parameters.Except(matchedParameters); return nonMatchedParameters.All(p => p.HasExplicitDefaultValue); }
private static bool CanBeMadeConst(LocalDeclarationStatementSyntax localDeclaration, SemanticModel semanticModel) { // already const? if (localDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword)) { return false; } // Ensure that all variables in the local declaration have initializers that // are assigned with constant values. foreach (var variable in localDeclaration.Declaration.Variables) { var initializer = variable.Initializer; if (initializer == null) { return false; } var constantValue = semanticModel.GetConstantValue(initializer.Value); if (!constantValue.HasValue) { return false; } var variableTypeName = localDeclaration.Declaration.Type; var variableType = semanticModel.GetTypeInfo(variableTypeName).ConvertedType; // Ensure that the initializer value can be converted to the type of the // local declaration without a user-defined conversion. var conversion = semanticModel.ClassifyConversion(initializer.Value, variableType); if (!conversion.Exists || conversion.IsUserDefined) { return false; } // Special cases: // * If the constant value is a string, the type of the local declaration // must be System.String. // * If the constant value is null, the type of the local declaration must // be a reference type. if (constantValue.Value is string) { if (variableType.SpecialType != SpecialType.System_String) { return false; } } else if (variableType.IsReferenceType && constantValue.Value != null) { return false; } } // Perform data flow analysis on the local declaration. var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(localDeclaration); // Retrieve the local symbol for each variable in the local declaration // and ensure that it is not written outside of the data flow analysis region. foreach (var variable in localDeclaration.Declaration.Variables) { var variableSymbol = semanticModel.GetDeclaredSymbol(variable); if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol)) { return false; } } return true; }