Olá pessoal. Hoje temos outro projeto da Microsoft em cheque. Pelo título deste artigo, você pode supor que desta vez os desenvolvedores não "nos agradaram" com um grande número de erros. Esperamos que os autores do projeto não se ofendam com o título. Afinal, um pequeno número de erros é ótimo, não é? No entanto, ainda conseguimos encontrar algo intrigante no código do Azure PowerShell. Sugerimos conhecer os recursos deste projeto e verificar os erros encontrados no analisador PVS-Studio C #.
Sobre o projeto
O Azure PowerShell é um conjunto de comandos (
cmdlet ) que permite gerenciar os recursos do
Azure diretamente na linha de comando do
PowerShell . O principal objetivo deste conjunto é simplificar o processo de estudo e iniciar rapidamente o desenvolvimento do Azure. O Azure PowerShell fornece aos administradores e desenvolvedores recursos atraentes para criar, implantar e gerenciar aplicativos do Microsoft Azure.
O Azure PowerShell é desenvolvido no ambiente .NET Standard, com suporte do PowerShell 5.1 para Windows e PowerShell 6.xe posterior para todas as plataformas. O
código-fonte do Azure PowerShell está disponível no GitHub.
Recentemente, tenho recebido frequentemente projetos da Microsoft para verificação. Na minha opinião, a qualidade desses projetos geralmente é de primeira. Embora, é claro, não sem exceções, conforme descrito no artigo "
WinForms: Erros, Holmes ". Mas desta vez está tudo bem. O projeto é grande: 6845 arquivos de código-fonte .cs contêm aproximadamente 700.000 linhas, excluindo as em branco (não levei em consideração testes e avisos do terceiro nível de certeza). Foram encontrados muito poucos erros para essa quantidade de código: não mais que cem. Havia muitos casos semelhantes, então escolhi os mais interessantes para o artigo. Como sempre, classifiquei os erros pelos números dos avisos do PVS-Studio.
Também me deparei com alguns fragmentos de código que pareciam erros, mas não podiam ser reconhecidos como definitivamente errôneos, pois não estou familiarizado o suficiente com as peculiaridades de desenvolvimento do PowerShell. Espero que entre os leitores haja especialistas nesta edição que me ajudarão. Vou descrevê-lo em detalhes abaixo.
Antes da parte do feedback, gostaria de mencionar a estrutura específica do projeto. O código-fonte do Azure PowerShell consiste em mais de setenta soluções do Visual Studio. Algumas soluções incluem projetos de outras. Essa estrutura atrasou um pouco a análise (não muito). Ainda assim, o cheque não causou outras dificuldades. Por conveniência, na mensagem de erro (entre colchetes), especificarei o nome da solução em que o erro foi encontrado.
Resultados da análise
V3001 Existem sub-expressões idênticas 'strTimespan.Contains ("M")' à esquerda e à direita da '||' 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")) .... }
Um exemplo de um erro bastante óbvio que apenas um desenvolvedor pode corrigir. Nesse caso, não está absolutamente claro se lidamos com a duplicação de código que afeta nada ou algo mais deve ocorrer em vez de
"M" em uma das duas últimas verificações.
V3001 Existem
subexpressões idênticas 'this.AggregationType! = Null' à esquerda e à direita do 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; .... }
Provavelmente não há erro aqui. Este é um exemplo de código redundante. Às vezes, esse código pode indicar falta de conhecimento do desenvolvedor. O ponto é que as verificações
this.AggregationType! = Null e
this.AggregationType.HasValue são idênticas. Basta usar apenas um deles (qualquer um). Pessoalmente, prefiro a opção com
HasValue: string aggregation = this.AggregationType.HasValue ? this.AggregationType.Value.ToString() : null;
V3003 O uso do
padrão 'if (A) {...} else if (A) {...}' foi detectado. Há uma probabilidade de presença de erro lógico. Verifique as linhas: 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 ); } .... }
Duas
outras se os blocos são absolutamente idênticos, incluindo a condição e o corpo do bloco. Esses erros geralmente são cometidos ao usar o método copiar e colar. A questão aqui é novamente a criticidade do erro. Se não for uma duplicação simples de código, pode ser a verificação necessária ausente e o conjunto de ações apropriado. O autor definitivamente precisa editar o código.
V3005 A variável 'this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent' é atribuída a si mesma. SetAzureVMOperatingSystemCommand.cs 298 (Compute)
public override void ExecuteCmdlet() { ....
O valor da propriedade é auto-atribuído. Veja a sua declaração:
[JsonProperty(PropertyName = "provisionVMAgent")] public bool? ProvisionVMAgent { get; set; }
A descrição
JsonProperty afirma: "Instrui o Newtonsoft.Json.JsonSerializer para sempre serializar o membro com o nome especificado." Parece que tudo é inocente e o erro óbvio foi cometido. O uso explícito
disso para acessar a propriedade também é bastante confuso. Talvez outra variável não tenha sido especificada por engano em vez
disso. Mas não vamos tirar conclusões precipitadas. O fato é que me deparei com muitas dessas atribuições (uma propriedade é auto-atribuída). Aqui está um exemplo de uma atribuição, muito semelhante a um erro:
V3005 A variável 'this.LastHeartbeat' é atribuída a si mesma. PSFabricDetails.cs 804 (RecoveryServices)
public ASRInMageAzureV2SpecificRPIDetails( InMageAzureV2ReplicationDetails details) { this.LastHeartbeat = this.LastHeartbeat;
Vamos dar uma olhada mais de perto na segunda e subseqüentes atribuições. Na parte correta da expressão, os
detalhes ocorrem em vez
disso. Agora observe a declaração da propriedade
this.LastHeartbeat :
public DateTime? LastHeartbeat { get; set; }
Por fim, vamos encontrar a propriedade com o mesmo nome na classe
InMageAzureV2ReplicationDetails . Essa propriedade é declarada lá:
public class InMageAzureV2ReplicationDetails : ReplicationProviderSpecificSettings { .... [JsonProperty(PropertyName = "lastHeartbeat")] public DateTime? LastHeartbeat { get; set; } .... }
Bem, neste caso, estou disposto a admitir que é um erro real. Mas o que devemos fazer com os próximos avisos? Ao contrário de dois fragmentos de código anteriores, existem várias propriedades auto-atribuídas. Bem, isso parece menos com um erro:
- V3005 A variável 'this.ResourceGroupName' é atribuída a si mesma. RemoveAzureRmExpressRouteConnectionCommand.cs 84 (CognitiveServices)
- V3005 A variável 'this.ExpressRouteGatewayName' é atribuída a si mesma. RemoveAzureRmExpressRouteConnectionCommand.cs 85 (CognitiveServices)
- V3005 A variável 'this.Name' é atribuída a si mesma. 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; } .... } .... }
O método
Execute contém auto-atribuições de três propriedades em uma linha. Por exemplo, citei a declaração completa da classe
RemoveExpressRouteConnectionCommand e todos os seus atributos, bem como a declaração da propriedade
ResourceGroupName (outras duas propriedades são declaradas de maneira semelhante). Foram esses avisos que me fizeram pensar na pergunta: "É um erro?" Suspeito que alguma mágica interna do desenvolvimento do PowerShell possa estar acontecendo aqui. Espero que entre os leitores haja especialistas que sejam informados sobre esse assunto. Não estou pronto para tirar conclusões neste caso.
V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 259 (RecoveryServices)
private void StartRPITestFailover() { .... if (....) { .... } else { new ArgumentException( Resources .UnsupportedDirectionForTFO);
A palavra-chave
throw é omitida. E o comentário diz que a exceção precisa ser lançada. Encontrei vários erros semelhantes na solução
RecoveryServices :
- V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 305 (RecoveryServices)
- V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 278 (RecoveryServices)
- V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 322 (RecoveryServices)
- V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 421 (RecoveryServices)
- V3006 O objeto foi criado, mas não está sendo usado. A palavra-chave 'throw' pode estar ausente: throw new ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 452 (RecoveryServices)
A expressão
V3022 'apiType.HasValue' é sempre 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 ?
A lógica do trabalho foi quebrada. Se
apiType contiver um valor, o controle não alcançará a expressão de
retorno no final do método (todas as ramificações da
opção contêm
retorno ). Caso contrário, o método sempre retornará
PsApiManagementApiType.Http.ToString ("g") , enquanto o valor
apiType.Value.ToString ("g") nunca será retornado.
A expressão
V3022 'automationJob! = Null && automationJob == null' é sempre falsa. NodeConfigurationDeployment.cs 199 (automação)
public NodeConfigurationDeployment( ...., Management.Automation.Models.Job automationJob = null, ....) { .... if (automationJob != null && automationJob == null) return; .... }
Código contra-intuitivo. Dois cheques que se contradizem. Provavelmente, a segunda verificação de
nulo contém a variável errada.
A expressão
V3022 é sempre 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"); } .... }
O cheque é inútil e a exceção nunca será lançada. A condição requer a igualdade simultânea da variável
linkedServiceType para três valores diferentes. Os operadores && e || provavelmente ficarão confusos. Código fixo:
if (( linkedServiceType == LinkedServiceType.OnPremisesSqlLinkedService || linkedServiceType == LinkedServiceType.OnPremisesOracleLinkedService || linkedServiceType == LinkedServiceType.OnPremisesFileSystemLinkedService) && (value == null || value.Length == 0)) ....
A expressão
V3022 'Ekus == null' é sempre falsa. PSKeyVaultCertificatePolicy.cs 129 (KeyVault)
internal CertificatePolicy ToCertificatePolicy() { .... if (Ekus != null) { x509CertificateProperties.Ekus = Ekus == null ? null : new List<string>(Ekus); } .... }
Verificação redundante da variável
Ekus para
null . Provavelmente está bem, mas o código não parece bom.
V3023 Considere inspecionar esta expressão. A expressão é excessiva ou contém uma impressão incorreta. PolicyRetentionObjects.cs 207 (RecoveryServices)
public virtual void Validate() { if (RetentionTimes == null || RetentionTimes.Count == 0 || RetentionTimes.Count != 1) { throw new ArgumentException( Resources.InvalidRetentionTimesInPolicyException); } }
Aqui está uma verificação excessiva ou uma condição excessiva. A verificação
RetentionTimes.Count == 0 é inútil, pois depois disso, a verificação
RetentionTimes.Count! = 1 é a seguir.
V3025 Formato incorreto. É esperado um número diferente de itens de formato ao chamar a função 'Format'. Argumentos não 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))) { .... } .... }
Um erro na linha de formatação. O especificador
{0} é usado duas vezes e o método
Format recebe dois argumentos. Aqui está a versão correta:
if (this.ShouldProcess(this.Name, string.Format("Creating Log Alert Rule '{0}' in resource group {1}", this.Name, this.ResourceGroupName))) ....
Outro erro semelhante:
- V3025 Formato incorreto. É esperado um número diferente de itens de formato ao chamar a função 'Format'. Argumentos não utilizados: this.ResourceGroupName. RemoveScheduledQueryRuleCommand.cs 88 (Monitor)
V3042 Possível NullReferenceException. O '?' e '.' operadores são usados para acessar membros do objeto 'imageAndOsType' VirtualMachineScaleSetStrategy.cs 81 (Compute)
internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScaleSetConfig(...., ImageAndOsType imageAndOsType, ....) { .... VirtualMachineProfile = new VirtualMachineScaleSetVMProfile { OsProfile = new VirtualMachineScaleSetOSProfile { ...., WindowsConfiguration = imageAndOsType.CreateWindowsConfiguration(),
Ao criar o objeto
VirtualMachineScaleSetVMProfile , a variável
imageAndOsType é verificada como
nula sem nenhuma verificação preliminar. No entanto, além disso, ao criar o
VirtualMachineScaleSetStorageProfile , essa variável já é verificada usando o operador de acesso condicional mesmo duas vezes. O código não parece seguro.
V3042 Possível NullReferenceException. O '?' e '.' operadores são usados para acessar membros do 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(....);
Na execução normal e como resultado do tratamento de uma exceção, a variável
existenteContacts pode obter o valor
nulo , após o qual a execução continuará. Além disso, no código, essa variável é usada sem nenhum motivo específico.
V3066 Possível ordem incorreta de argumentos passada para o método 'PersistSyncServerRegistration': 'storageSyncServiceUid' e 'discoveryUri'. EcsManagementInteropClient.cs 364 (StorageSync)
public class EcsManagementInteropClient : IEcsManagement { .... public int PersistSyncServerRegistration(....) { return m_managementObject.PersistSyncServerRegistration( serviceUri, subscriptionId, storageSyncServiceName, resourceGroupName, clusterId, clusterName, storageSyncServiceUid,
O analisador suspeitou que a ordem dos argumentos do método
PersistSyncServerRegistration estivesse confusa. Declaração do 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 fato, algo está errado aqui com os argumentos número sete e oito. O autor deve verificar o código.
V3077 O configurador da propriedade 'GetGuid' não utiliza seu parâmetro 'value'. RecoveryServicesBackupCmdletBase.cs 54 (RecoveryServices)
public abstract class RecoveryServicesBackupCmdletBase : AzureRMCmdlet { .... static string _guid; protected static string GetGuid { get { return _guid; } set { _guid = Guid.NewGuid().ToString(); } } .... }
O setter não usa o parâmetro passado. Em vez disso, ele cria um novo GUID e o atribui ao campo
_guid . Eu acho que a maioria dos leitores concorda que esse código parece pelo menos feio. Essa construção não é muito conveniente de usar: ao (re) inicializar a propriedade
GetGuid , é necessário atribuir um valor falso a ela, o que não é muito óbvio. Mas, acima de tudo, fiquei divertido com a maneira como os autores usavam esse padrão. Há apenas um lugar onde o
GetGuid é tratado. Confira:
public override void ExecuteCmdlet() { .... var itemResponse = ServiceClientAdapter.CreateOrUpdateProtectionIntent( GetGuid ?? Guid.NewGuid().ToString(), ....); .... }
Brilhante!
V3091 Análise empírica. É possível que um erro de digitação esteja presente dentro da string literal: "ID do grupo de gerenciamento". A palavra 'Id' é suspeita. 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";
O analisador apontou para um possível erro na sequência atribuída para a constante
GroupName . A conclusão é baseada na análise empírica de outras atribuições, levando em consideração os nomes das variáveis. Penso que, neste caso, o analisador está certo e o valor das constantes
GroupName deve ser uma espécie de "nome do grupo de gerenciamento". Provavelmente, o erro ocorreu devido ao fato de o valor da constante
GroupId ter sido copiado, mas não alterado.
Outro erro semelhante:
- V3091 Análise empírica. É possível que um erro de digitação esteja presente dentro da string literal. A palavra 'Nome' é suspeita. ParamHelpMsgs.cs 153 (RecoveryServices)
V3093 O '|' O operador avalia os dois operandos. Talvez um curto-circuito '||' operador deve ser usado. PSKeyVaultCertificatePolicy.cs 114 (KeyVault)
internal CertificatePolicy ToCertificatePolicy() { .... if (!string.IsNullOrWhiteSpace(SubjectName) || DnsNames != null || Ekus != null || KeyUsage != null |
Nesse fragmento, pode ocorrer um erro e no bloco
if entre as duas últimas condições, o || operador pode ter sido usado. Mas, como costuma acontecer, apenas o desenvolvedor pode dar a resposta certa.
V3095 O objeto 'certificado' foi usado antes de ser verificado em relação a nulo. Verifique as linhas: 41, 43. CertificateInfo.cs 41 (Automação)
public CertificateInfo( ...., Azure.Management.Automation.Models.Certificate certificate) { .... this.Name = certificate.Name; if (certificate == null) return; .... }
Classic. Primeiro, o objeto é usado e somente depois disso a referência é verificada como
nula . Encontramos esses erros com
muita frequência . Vamos considerar outro erro semelhante.
V3095 O objeto 'clusterCred' foi usado antes de ser verificado em relação a nulo. Verifique as linhas: 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) .... }
Aqui estão alguns erros semelhantes:
- V3095 O objeto '_profile' foi usado antes de ser verificado contra nulo. Verifique as linhas: 47, 49. RMProfileClient.cs 47 (Contas)
- V3095 O objeto 'this.LoadBalancer.BackendAddressPools' foi usado antes de ser verificado como nulo. Verifique as linhas: 56, 63. AddAzureRmLoadBalancerBackendAddressPoolConfigCommand.cs 56 (CognitiveServices)
- De um modo geral, vi muitos erros da V3095 no código do Azure PowerShell. Mas todos eles são bem parecidos, então não vou me debruçar sobre esse assunto.
V3125 O objeto 'startTime' foi usado após a verificação contra nulo. Verifique as linhas: 1752, 1738. AutomationPSClientDSC.cs 1752 (Automation)
private string GetNodeReportListFilterString( ...., DateTimeOffset? startTime, ...., DateTimeOffset? lastModifiedTime) { .... if (startTime.HasValue) { odataFilter.Add("properties/startTime ge " + this.FormatDateTime(startTime.Value));
Também é um tipo bastante amplo de erros. A variável
startTime é verificada quanto à presença de valor quando usada pela primeira vez. Mas isso não é feito no uso subsequente. Bem, a situação pode ser ainda pior. Olhe para o segundo
se bloco. Eu acho que a variável
startTime não deve estar aqui. Em primeiro lugar, não há verificação de presença de valor antes de seu uso. Em segundo lugar, a string formada para ser passada para o método
Add também confirma minha sugestão. Outra variável
(lastModifiedTime ) é mencionada na primeira parte dessa string.
V3125 O objeto 'firstPage' foi usado depois de verificado contra nulo. Verifique as linhas: 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))
Outro erro óbvio. A variável
firstPage é usada sem segurança, apesar do fato de que anteriormente no código essa variável já é usada, sendo verificada preliminarmente como
nula .
Encontrei ainda mais avisos da
V3125 no código do Azure PowerShell que os da
V3095 descritos acima. Todos eles também são do mesmo tipo. Eu acho que dois deles que consideramos são suficientes.
V3137 A variável 'apiVersionSetId' é atribuída, mas não é usada no final da função. 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))
O analisador relata que a variável local
apiVersionSetId foi inicializada, mas não utilizada de forma alguma. Geralmente, esse padrão indica um erro. Eu acho que, nesse caso, é mais provável que seja um erro, especialmente levando em conta o fato de que o nome da variável local
apiVersionSetId e o nome da propriedade
ApiVersionSetId diferem apenas no caso da primeira letra. Dê uma olhada no código. Depois de inicializar a
propriedade apiVersionSetId (de uma maneira ou de outra), somente a propriedade
ApiVersionSetId é usada ainda mais no código. Parece extremamente suspeito.
V3137 A variável 'cacheId' é atribuída, mas não é usada no final da função. 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);
Este é o caso quase igual ao descrito anteriormente. A variável local
cacheId não é usada após a inicialização de forma alguma. Em vez disso, outra propriedade com um nome muito semelhante
CacheId é usada. Não sei ao certo, pode ser que seja apenas um padrão de programação dos desenvolvedores do Azure PowerShell. Enfim, parece um erro.
V3143 O parâmetro 'value' é reescrito dentro de um
configurador de propriedades e não é usado depois disso. 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; }
O campo
partnerType é declarado da seguinte maneira:
Apesar do nome da solução (LogicApp) em que um erro foi detectado, não encontro lógica. Modificar
valor no setter não é uma ocorrência rara, mas, neste caso, lida com a perda do valor original. Parece estranho. No código, a propriedade é lida apenas uma vez. Talvez, tenhamos que pedir novamente conselhos de especialistas. Talvez eu simplesmente não entenda. O ponto é que me deparei com vários mesmos padrões:
- V3143 O parâmetro 'value' é reescrito dentro de um configurador de propriedades e não é usado depois disso. NewAzureIntegrationAccountSchemaCommand.cs 79 (LogicApp)
- V3143 O parâmetro 'value' é reescrito dentro de um configurador de propriedades e não é usado depois disso. NewAzureIntegrationAccountSchemaCommand.cs 87 (LogicApp)
- V3143 O parâmetro 'value' é reescrito dentro de um configurador de propriedades e não é usado depois disso. UpdateAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)
- V3143 O parâmetro 'value' é reescrito dentro de um configurador de propriedades e não é usado depois disso. UpdateAzureIntegrationAccountSchemaCommand.cs 80 (LogicApp)
- V3143 O parâmetro 'value' é reescrito dentro de um configurador de propriedades e não é usado depois disso. UpdateAzureIntegrationAccountSchemaCommand.cs 88 (LogicApp)
Conclusão
Esses são todos os erros interessantes encontrados no código do Azure PowerShell. Entusiastas e interessados podem revisar os próprios erros neste (ou em qualquer outro) projeto. Eu provavelmente poderia perder algo excêntrico. Para fazer a revisão, você só precisa baixar e instalar o
PVS-Studio .
Obrigado por ler até o fim. E, é claro, código sem erros para todos!