Hola a todos Hoy tenemos otro proyecto de Microsoft en la prueba. Por el título del artículo, puede adivinar que esta vez los desarrolladores no pudieron complacernos con una gran cantidad de errores. Esperamos que los autores del proyecto no se ofendan por el nombre. Después de todo, un pequeño número de errores es excelente, ¿no? Sin embargo, se encontró algo interesante en el código de Azure PowerShell. Le sugerimos que se familiarice con las características de este proyecto y observe los errores encontrados utilizando el analizador PV # C PVS-Studio.
Sobre el proyecto
Azure PowerShell es un cmdlet que le permite administrar recursos de
Azure directamente desde la línea de comandos de
PowerShell . El objetivo principal de este conjunto es simplificar el aprendizaje y el inicio rápido del desarrollo para Azure. Azure PowerShell proporciona a los administradores y desarrolladores características potentes para crear, implementar y administrar aplicaciones de Microsoft Azure.
Azure PowerShell está desarrollado en el entorno .NET Standard y es compatible con PowerShell 5.1 para Windows y PowerShell 6.xy superior para todas las plataformas. El
código fuente de Azure PowerShell está disponible en GitHub.
Recientemente, los proyectos de Microsoft a menudo me llaman la atención. En mi opinión, la calidad de estos proyectos suele ser la mejor. Aunque, por supuesto, no sin excepciones, como fue el artículo "
WinForms: errores, Holmes ". Sin embargo, esta vez todo es normal. El proyecto es grande: el código fuente de 6845 archivos .cs contiene aproximadamente 700 mil líneas, excluyendo las vacías (pruebas, así como advertencias del tercer nivel de confiabilidad, no lo tuve en cuenta). Hubo muy pocos errores para tal volumen de código: no más de cien. Hay bastantes situaciones del mismo tipo, por lo que para el artículo seleccioné los aspectos más interesantes. Los errores, como hago habitualmente, se ordenan por los números de diagnóstico de PVS-Studio.
También encontré fragmentos de código que parecen errores, pero no pude llegar a una conclusión inequívoca sobre la existencia de un problema real, ya que no estoy lo suficientemente familiarizado con las características de diseño de PowerShell. Espero que entre los lectores haya expertos en este tema y que me ayuden. Sobre esto a continuación.
Antes del comienzo de la "sesión informativa", noto la característica de diseño en términos de su estructura. El código fuente de Azure PowerShell consta de más de setenta soluciones de Visual Studio. Algunas soluciones incluyen proyectos de otras soluciones. Tal estructura ralentizó el análisis un poco (no mucho). El resto de la verificación no causó dificultades. Por conveniencia, en la línea del mensaje de error (entre paréntesis) indicaré el nombre de la solución en la que se detectó este error.
Resultados de validación
V3001 Hay
subexpresiones idénticas 'strTimespan.Contains ("M")' a la izquierda y a la derecha de '||' operador AzureServiceBusCmdletBase.cs 187 (EventGrid)
public static TimeSpan ParseTimespan(string strTimespan) { .... if (strTimespan.Contains("P") || strTimespan.Contains("D") || strTimespan.Contains("T") || strTimespan.Contains("H") || strTimespan.Contains("M") || strTimespan.Contains("M")) .... }
Un ejemplo de un error bastante obvio, que solo el desarrollador puede solucionar. En este caso, es completamente incomprensible si estamos lidiando con la duplicación de código que no afecta nada, o en lugar de
"M" , debería aparecer algo más en una de las últimas dos comprobaciones.
V3001 Hay
subexpresiones idénticas 'this.AggregationType! = Null' a la izquierda y a la derecha del operador '&&'. GetAzureRmMetricCommand.cs 156 (Monitor)
public AggregationType? AggregationType { get; set; } .... protected override void ProcessRecordInternal() { .... string aggregation = (this.AggregationType != null && this.AggregationType.HasValue) ? this.AggregationType.Value.ToString() : null; .... }
Probablemente no haya ningún error aquí. Este es un ejemplo de código redundante. A veces, dicho código puede indicar un nivel insuficiente de conocimiento del desarrollador. El hecho es que
this.AggregationType! = Null y
this.AggregationType.HasValue son idénticos. Es suficiente usar uno de ellos (cualquiera). Personalmente, prefiero la
opción HasValue :
string aggregation = this.AggregationType.HasValue ? this.AggregationType.Value.ToString() : null;
V3003 Se usó el
patrón 'if (A) {...} else if (A) {...}'. Hay una probabilidad de presencia de error lógico. Líneas de verificación: 152, 163. GetAzureRmRecoveryServicesBackupProtectionPolicy.cs 152 (RecoveryServices)
public override void ExecuteCmdlet() { .... if( WorkloadType == Models.WorkloadType.AzureVM ) { .... } .... else if( WorkloadType == Models.WorkloadType.AzureFiles ) { if( BackupManagementType != Models.BackupManagementType.AzureStorage ) { throw new ArgumentException( Resources.AzureFileUnsupportedBackupManagementTypeException ); } serviceClientProviderType = ServiceClientHelpers. GetServiceClientProviderType( Models.WorkloadType.AzureFiles ); } else if( WorkloadType == Models.WorkloadType.AzureFiles ) { if( BackupManagementType != Models.BackupManagementType.AzureStorage ) { throw new ArgumentException( Resources.AzureFileUnsupportedBackupManagementTypeException ); } serviceClientProviderType = ServiceClientHelpers. GetServiceClientProviderType( Models.WorkloadType.AzureFiles ); } .... }
Los
otros dos
si los bloques son absolutamente idénticos, incluyendo tanto la condición como el cuerpo del bloque. Tales errores generalmente se hacen cuando se utiliza el método de copiar y pegar en el trabajo. La pregunta nuevamente es la importancia de este error. Si esto no es una simple duplicación de código, entonces podemos hablar sobre la falta de la verificación necesaria y el conjunto de acciones correspondiente. El autor necesita editar el código.
V3005 La variable 'this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent' se asigna a sí misma. SetAzureVMOperatingSystemCommand.cs 298 (Calcular)
public override void ExecuteCmdlet() { ....
El valor de la propiedad se asigna a sí mismo. Echa un vistazo a su anuncio:
[JsonProperty(PropertyName = "provisionVMAgent")] public bool? ProvisionVMAgent { get; set; }
La descripción de
JsonProperty dice "Indica a Newtonsoft.Json.JsonSerializer que siempre serialice al miembro con el nombre especificado". Parece que todo es simple y hay un error obvio. También es confuso el uso explícito de
esto para acceder a una propiedad. Quizás, por error, no se especificó alguna otra variable en lugar de
esto . Pero por ahora, no sacaremos conclusiones. El hecho es que en el código de Azure PowerShell conocí muchas de esas asignaciones (la propiedad se asigna a sí misma). Aquí hay otro ejemplo de una tarea que es muy similar a un error:
V3005 La variable 'this.LastHeartbeat' se asigna a sí misma. PSFabricDetails.cs 804 (RecoveryServices)
public ASRInMageAzureV2SpecificRPIDetails( InMageAzureV2ReplicationDetails details) { this.LastHeartbeat = this.LastHeartbeat;
Presta atención a la segunda y posteriores asignaciones. En el lado derecho de la expresión, no es
esto lo que aparece, sino
detalles .
Eche un vistazo a la declaración de
esta propiedad
LastHeartbeat :
public DateTime? LastHeartbeat { get; set; }
Finalmente, busque una propiedad con el mismo nombre en la clase
InMageAzureV2ReplicationDetails . Tal propiedad se declara allí:
public class InMageAzureV2ReplicationDetails : ReplicationProviderSpecificSettings { .... [JsonProperty(PropertyName = "lastHeartbeat")] public DateTime? LastHeartbeat { get; set; } .... }
Bueno, en este caso, estoy listo para admitir que esta activación es un verdadero error. Pero, ¿qué hacer con los siguientes factores desencadenantes? En ellos, a diferencia de los dos fragmentos de código anteriores, hay una asignación múltiple de propiedades para ellos mismos. Esto ya es menos como un error:
- V3005 La variable 'this.ResourceGroupName' se asigna a sí misma. RemoveAzureRmExpressRouteConnectionCommand.cs 84 (CognitiveServices)
- V3005 La variable 'this.ExpressRouteGatewayName' se asigna a sí misma. RemoveAzureRmExpressRouteConnectionCommand.cs 85 (CognitiveServices)
- V3005 La variable 'this.Name' se asigna a sí misma. RemoveAzureRmExpressRouteConnectionCommand.cs 86 (CognitiveServices)
[Cmdlet(VerbsCommon.Remove, ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "ExpressRouteConnection", DefaultParameterSetName = CortexParameterSetNames.ByExpressRouteConnectionName, SupportsShouldProcess = true), OutputType(typeof(bool))] public class RemoveExpressRouteConnectionCommand : ExpressRouteConnectionBaseCmdlet { [Parameter( Mandatory = true, ParameterSetName = CortexParameterSetNames.ByExpressRouteConnectionName, HelpMessage = "The resource group name.")] [ResourceGroupCompleter] [ValidateNotNullOrEmpty] public string ResourceGroupName { get; set; } .... public override void Execute() { if (....) { this.ResourceGroupName = this.ResourceGroupName; this.ExpressRouteGatewayName = this.ExpressRouteGatewayName; this.Name = this.Name; } .... } .... }
El método
Execute contiene tres asignaciones consecutivas de propiedades para ellos mismos. Por si acaso, di una declaración completa de la clase
RemoveExpressRouteConnectionCommand con todos sus atributos, así como una declaración de la propiedad
ResourceGroupName (las otras dos propiedades se declaran de la misma manera). Fue tan desencadenante que me hizo pensar en la pregunta: "¿Es esto un error?" Sospecho que aquí puede ocurrir algún tipo de magia interna del desarrollo de PowerShell. Espero que entre los lectores haya expertos con conocimientos en este tema. No estoy listo para hacer ninguna conclusión en este caso.
V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 259 (RecoveryServices)
private void StartRPITestFailover() { .... if (....) { .... } else { new ArgumentException( Resources .UnsupportedDirectionForTFO);
Se omitió la palabra clave de
lanzamiento . Además, el comentario dice que la excepción debería ser lanzada. En la solución
RecoveryServices , encontré varios errores más similares:
- V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 305 (RecoveryServices)
- V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 278 (RecoveryServices)
- V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 322 (RecoveryServices)
- V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 421 (RecoveryServices)
- V3006 El objeto fue creado pero no se está utilizando. Podría faltar la palabra clave 'throw': lanzar una nueva ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 452 (RecoveryServices)
V3022 La expresión 'apiType.HasValue' siempre es falsa. ApiManagementClient.cs 1134 (ApiManagement)
private string GetApiTypeForImport(...., PsApiManagementApiType? apiType) { .... if (apiType.HasValue) { switch(apiType.Value) { case PsApiManagementApiType.Http: return SoapApiType.SoapToRest; case PsApiManagementApiType.Soap: return SoapApiType.SoapPassThrough; default: return SoapApiType.SoapPassThrough; } } return apiType.HasValue ?
Se viola la lógica del trabajo. Si
apiType contiene un valor, entonces el control no alcanzará la expresión de
retorno al final del método (todas las ramas del
interruptor contienen
retorno ). De lo contrario, el método siempre devolverá
PsApiManagementApiType.Http.ToString ("g") y
apiType.Value.ToString ("g") , respectivamente, nunca se devolverán.
V3022 La expresión 'automationJob! = Null && automationJob == null' siempre es falsa. NodeConfigurationDeployment.cs 199 (Automatización)
public NodeConfigurationDeployment( ...., Management.Automation.Models.Job automationJob = null, ....) { .... if (automationJob != null && automationJob == null) return; .... }
El código paradójico. Dos controles que se contradicen entre sí. Probablemente la segunda comprobación de igualdad
nula contiene la variable incorrecta.
V3022 La expresión siempre es falsa. DataFactoryClient.Encrypt.cs 37 (DataFactory)
public virtual string OnPremisesEncryptString(....) { .... if ( linkedServiceType == LinkedServiceType.OnPremisesSqlLinkedService && linkedServiceType == LinkedServiceType.OnPremisesOracleLinkedService && linkedServiceType == LinkedServiceType.OnPremisesFileSystemLinkedService && (value == null || value.Length == 0)) { throw new ArgumentNullException("value"); } .... }
La comprobación no tiene sentido, y nunca se lanzará una excepción. La condición requiere la igualdad simultánea de la variable
LinkedServiceType con tres valores diferentes. Los operadores && y || probablemente estén confundidos. Código corregido:
if (( linkedServiceType == LinkedServiceType.OnPremisesSqlLinkedService || linkedServiceType == LinkedServiceType.OnPremisesOracleLinkedService || linkedServiceType == LinkedServiceType.OnPremisesFileSystemLinkedService) && (value == null || value.Length == 0)) ....
V3022 La expresión 'Ekus == null' siempre es falsa. PSKeyVaultCertificatePolicy.cs 129 (KeyVault)
internal CertificatePolicy ToCertificatePolicy() { .... if (Ekus != null) { x509CertificateProperties.Ekus = Ekus == null ? null : new List<string>(Ekus); } .... }
Comprobación superflua de la variable
Ekus para igualdad
nula . Probablemente no hay nada malo, pero el código se ve feo.
V3023 Considere inspeccionar esta expresión. La expresión es excesiva o contiene un error de imprenta. PolicyRetentionObjects.cs 207 (RecoveryServices)
public virtual void Validate() { if (RetentionTimes == null || RetentionTimes.Count == 0 || RetentionTimes.Count != 1) { throw new ArgumentException( Resources.InvalidRetentionTimesInPolicyException); } }
Control excesivo o condición errónea. Verificar
RetentionTimes.Count == 0 no tiene sentido, porque después de eso, verifique
RetentionTimes.Count! = 1 .
V3025 Formato incorrecto. Se espera un número diferente de elementos de formato al llamar a la función 'Formatear'. Argumentos no utilizados: this.ResourceGroupName. NewScheduledQueryRuleCommand.cs 117 (Monitor)
protected override void ProcessRecordInternal() { .... if (this.ShouldProcess(this.Name, string.Format("Creating Log Alert Rule '{0}' in resource group {0}", this.Name, this.ResourceGroupName))) { .... } .... }
Error en la cadena de formato. El calificador
{0} se usa dos veces, con dos argumentos pasados al método
Format . La opción correcta:
if (this.ShouldProcess(this.Name, string.Format("Creating Log Alert Rule '{0}' in resource group {1}", this.Name, this.ResourceGroupName))) ....
Otro error similar:
- V3025 Formato incorrecto. Se espera un número diferente de elementos de formato al llamar a la función 'Formatear'. Argumentos no utilizados: this.ResourceGroupName. RemoveScheduledQueryRuleCommand.cs 88 (Monitor)
V3042 Posible NullReferenceException. El '?.' y '.' Los operadores se utilizan para acceder a los miembros del objeto 'imageAndOsType' VirtualMachineScaleSetStrategy.cs 81 (Calcular)
internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScaleSetConfig(...., ImageAndOsType imageAndOsType, ....) { .... VirtualMachineProfile = new VirtualMachineScaleSetVMProfile { OsProfile = new VirtualMachineScaleSetOSProfile { ...., WindowsConfiguration = imageAndOsType.CreateWindowsConfiguration(),
Al crear un
VirtualMachineScaleSetVMProfile, la variable
imageAndOsType se usa sin verificar
nulo . Sin embargo, al crear
VirtualMachineScaleSetStorageProfile , esta variable ya se verifica utilizando el operador de acceso condicional, y dos veces. El código parece inseguro.
V3042 Posible NullReferenceException. El '?.' y '.' Los operadores se utilizan para acceder a los miembros del objeto 'existenteContacts' RemoveAzureKeyVaultCertificateContact.cs 123 (KeyVault)
public override void ExecuteCmdlet() { .... List<PSKeyVaultCertificateContact> existingContacts; try { existingContacts = this.DataServiceClient. GetCertificateContacts(VaultName)?.ToList(); } catch (KeyVaultErrorException exception) { .... existingContacts = null; } foreach (var email in EmailAddress) { existingContacts.RemoveAll(....);
Como en el caso de la ejecución normal, y como resultado de manejar la excepción, la variable de contactos
existente puede quedar
nula , después de lo cual el trabajo continuará. Además en el código, esta variable se usa sin ninguna verificación.
V3066 Posible orden incorrecto de argumentos pasados al método 'PersistSyncServerRegistration': 'storageSyncServiceUid' y 'discoveryUri'. EcsManagementInteropClient.cs 364 (StorageSync)
public class EcsManagementInteropClient : IEcsManagement { .... public int PersistSyncServerRegistration(....) { return m_managementObject.PersistSyncServerRegistration( serviceUri, subscriptionId, storageSyncServiceName, resourceGroupName, clusterId, clusterName, storageSyncServiceUid,
El analizador sospechaba que el orden de pasar argumentos al método
PersistSyncServerRegistration era
confuso . Declaración del método:
public interface IEcsManagement : IDisposable { .... int PersistSyncServerRegistration( [In, MarshalAs(UnmanagedType.BStr)] string serviceUri, [In, MarshalAs(UnmanagedType.BStr)] string subscriptionId, [In, MarshalAs(UnmanagedType.BStr)] string storageSyncServiceName, [In, MarshalAs(UnmanagedType.BStr)] string resourceGroupName, [In, MarshalAs(UnmanagedType.BStr)] string clusterId, [In, MarshalAs(UnmanagedType.BStr)] string clusterName, [In, MarshalAs(UnmanagedType.BStr)] string discoveryUri,
De hecho, algo está mezclado aquí con los argumentos número siete y ocho. Se requiere la verificación del código por parte del autor.
V3077 El configurador de la propiedad 'GetGuid' no utiliza su parámetro 'valor'. RecoveryServicesBackupCmdletBase.cs 54 (RecoveryServices)
public abstract class RecoveryServicesBackupCmdletBase : AzureRMCmdlet { .... static string _guid; protected static string GetGuid { get { return _guid; } set { _guid = Guid.NewGuid().ToString(); } } .... }
El setter no utiliza el parámetro transmitido. En cambio, obtienen un nuevo GUID y lo asignan al campo
_guid . Creo que la mayoría de los lectores estarán de acuerdo en que ese código se ve al menos feo. El uso de tal construcción no es del todo conveniente: para (re) inicializar la propiedad
GetGuid , debe asignarle un valor falso, que es completamente obvio. Pero, sobre todo, me divertía el momento en que los propios autores utilizan esta construcción. Solo hay un lugar en el código donde
funciona GetGuid . Echa un vistazo:
public override void ExecuteCmdlet() { .... var itemResponse = ServiceClientAdapter.CreateOrUpdateProtectionIntent( GetGuid ?? Guid.NewGuid().ToString(), ....); .... }
Genial
V3091 Análisis empírico. Es posible que haya un error tipográfico dentro del literal de cadena: "Id. De grupo de administración". La palabra 'Id' es sospechosa. Constants.cs 36 (Recursos)
public class HelpMessages { public const string SubscriptionId = "Subscription Id of the subscription associated with the management"; public const string GroupId = "Management Group Id";
El analizador indicó un posible error en la cadena asignada para la constante
GroupName . La conclusión se basa en un análisis empírico de otras tareas teniendo en cuenta los nombres de las variables. Creo que en este caso el analizador tiene razón, y el valor de la constante
GroupName debería ser "Nombre del grupo de administración". El error probablemente fue causado por el hecho de que se
copió el valor de la constante
GroupId , pero se olvidaron de cambiarlo.
Otro error similar:
- V3091 Análisis empírico. Es posible que haya un error tipográfico dentro del literal de cadena. La palabra 'Nombre' es sospechosa. ParamHelpMsgs.cs 153 (RecoveryServices)
V3093 El '|' El operador evalúa ambos operandos. Quizás un cortocircuito '||' operador debe utilizarse en su lugar. PSKeyVaultCertificatePolicy.cs 114 (KeyVault)
internal CertificatePolicy ToCertificatePolicy() { .... if (!string.IsNullOrWhiteSpace(SubjectName) || DnsNames != null || Ekus != null || KeyUsage != null |
Existe la sospecha de que se ha cometido un error, y el operador || también debe utilizarse entre las últimas condiciones en el bloque
if . La respuesta exacta, como suele suceder, solo puede ser dada por el desarrollador.
V3095 El objeto 'certificado' se usó antes de que se verificara como nulo. Líneas de verificación: 41, 43. CertificateInfo.cs 41 (Automatización)
public CertificateInfo( ...., Azure.Management.Automation.Models.Certificate certificate) { .... this.Name = certificate.Name; if (certificate == null) return; .... }
Clásico Primero se usa el objeto, y solo luego se verifica que el enlace sea
nulo . Nos encontramos con tales errores
muy a menudo . Considere otro error similar.
V3095 El objeto 'clusterCred' se usó antes de que se verificara como nulo. Líneas de verificación: 115, 118. InvokeHiveCommand.cs 115 (HDInsight)
public override void ExecuteCmdlet() { .... _credential = new BasicAuthenticationCloudCredentials { Username = clusterCred.UserName, Password = clusterCred.Password.ConvertToString() }; if (clusterConnection == null || clusterCred == null) .... }
Y un par de errores más similares:
- V3095 El objeto '_profile' se usó antes de que se verificara como nulo. Líneas de verificación: 47, 49. RMProfileClient.cs 47 (Cuentas)
- V3095 El objeto 'this.LoadBalancer.BackendAddressPools' se usó antes de que se verificara como nulo. Líneas de verificación: 56, 63. AddAzureRmLoadBalancerBackendAddressPoolConfigCommand.cs 56 (CognitiveServices)
- En general, en el código de Azure PowerShell, me encontré con muchos más errores de V3095 . Pero todos son bastante similares, por lo que no me detendré en esto con más detalle.
V3125 El objeto 'startTime' se usó después de que se verificó contra nulo. Líneas de verificación: 1752, 1738. AutomationPSClientDSC.cs 1752 (Automatización)
private string GetNodeReportListFilterString( ...., DateTimeOffset? startTime, ...., DateTimeOffset? lastModifiedTime) { .... if (startTime.HasValue) { odataFilter.Add("properties/startTime ge " + this.FormatDateTime(startTime.Value));
También es un tipo de error bastante común. La variable
startTime se verificó para el valor en el primer uso. La próxima vez que use esto, no lo haga. Pero podría ser aún peor. Echa un vistazo al segundo bloque
if . Creo que no debería haber una variable
startTime en
absoluto . Esto se indica tanto por la ausencia de su comprobación de la presencia de un valor antes de su uso, como por la cadena formada para pasar al método
Add . La primera parte de esta línea menciona otra variable (
lastModifiedTime ).
V3125 El objeto 'firstPage' se usó después de que se verificó contra nulo. Líneas de verificación: 113, 108. IntegrationAccountAgreementOperations.cs 113 (LogicApp)
public IList<IntegrationAccountAgreement> ListIntegrationAccountAgreements(....) { var compositeList = new List<IntegrationAccountAgreement>(); var firstPage = this.LogicManagementClient. IntegrationAccountAgreements.List(....); if (firstPage != null) { compositeList.AddRange(firstPage); } if (!string.IsNullOrEmpty(firstPage.NextPageLink))
Otro error obvio. La variable
firstPage se usa de forma insegura, aunque anteriormente en el código hay un uso de esta variable con una comprobación preliminar de
nulo .
V3125 en el código Azure PowerShell fue aún más
exitoso que
V3095 descrito anteriormente. Todos ellos también son del mismo tipo. Creo que podemos limitarnos a los dos que examinamos.
V3137 La variable 'apiVersionSetId' se asigna pero no se usa al final de la función. GetAzureApiManagementApiVersionSet.cs 69 (ApiManagement)
public String ApiVersionSetId { get; set; } .... public override void ExecuteApiManagementCmdlet() { .... string apiVersionSetId; if (ParameterSetName.Equals(ContextParameterSet)) { .... apiVersionSetId = ApiVersionSetId; } else { apiVersionSetId = ....; } if (string.IsNullOrEmpty(ApiVersionSetId))
El analizador informa que la variable local
apiVersionSetId se ha inicializado, pero no se ha utilizado. A menudo, este patrón indica un error. Creo que en este caso la probabilidad de error es alta, dado que el nombre de la variable local
apiVersionSetId y el nombre de la propiedad
ApiVersionSetId difieren solo en el caso de la primera letra. Echa un vistazo al código. Después de inicializar
apiVersionSetId (de una forma u otra), solo se
usa la propiedad
ApiVersionSetId en el código. Muy, muy sospechoso.
V3137 La variable 'cacheId' se asigna pero no se usa al final de la función. RemoveAzureApiManagementCache.cs 94 (ApiManagement)
public String CacheId { get; set; } .... public override void ExecuteApiManagementCmdlet() { .... string cacheId; if (....) { .... cacheId = InputObject.CacheId; } else if (....) { .... cacheId = cache.CacheId; } else { .... cacheId = CacheId; } var actionDescription = string.Format(...., CacheId);
La situación, casi exactamente repitiendo lo considerado anteriormente. La variable local
cacheId no se usa después de la inicialización. En su lugar, usan una propiedad con un nombre muy similar,
CacheId . No sé, tal vez este sea un patrón entre los desarrolladores de Azure PowerShell. Pero parece un error.
V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. NewAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)
[Parameter(Mandatory = false, HelpMessage = "The integration account partner type.", ValueFromPipelineByPropertyName = false)] [ValidateSet("B2B", IgnoreCase = false)] [ValidateNotNullOrEmpty] public string PartnerType { get { return this.partnerType; } set { value = this.partnerType; }
El campo
partnerType se declara así:
Al contrario del nombre de la solución en la que se detectó este error (LogicApp), no veo la lógica aquí. Usar el
valor en un setter para grabar no es una ocurrencia tan rara, pero en este caso estamos hablando de perder el valor original. Se ve raro El código tiene un solo acceso de lectura a esta propiedad. Quizás deberías buscar nuevamente el asesoramiento de expertos. Tal vez no entiendo algo. El hecho es que conocí algunos más de los mismos patrones exactos:
- V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. NewAzureIntegrationAccountSchemaCommand.cs 79 (LogicApp)
- V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. NewAzureIntegrationAccountSchemaCommand.cs 87 (LogicApp)
- V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. UpdateAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)
- V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. UpdateAzureIntegrationAccountSchemaCommand.cs 80 (LogicApp)
- V3143 El parámetro 'valor' se reescribe dentro de un establecedor de propiedades, y no se usa después de eso. UpdateAzureIntegrationAccountSchemaCommand.cs 88 (LogicApp)
Conclusión
Esos son todos los errores interesantes que se encontraron en el código de Azure PowerShell.
Entusiastas y solo interesados, sugiero realizar un estudio independiente de errores en el código de este (o cualquier otro) proyecto. Probablemente podría haber perdido algo más interesante. Para hacer esto, simplemente descargue e instale PVS-Studio .Gracias por leer Un código sin código!
Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace a la traducción: Sergey Khrenov.
Azure PowerShell: mayormente inofensivo .