XL 2016 Analyse de Code VBA : Variables inutilisées

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

crocrocro

XLDnaute Impliqué
Bonjour à tous,

je n'ai pas réussi à trouver,
- soit un logiciel gratuit (le logiciel MZ-Tools dans sa version actuelle V8 est payant, à l'essai pendant 30 jours),
- soit un code dans les forums
qui permette de lister les variables, constantes, procédures inutilisées dans un projet VBA, en tenant compte évidemment de la portée des déclarations.

Quelqu'un a peut-être la solution.
Merci d'avance pour vos retours
.
 
Solution
Bonsoir,

en pj mon fichier de bricolage.

[EDIT du 13/03] : Il ne répond pas totalement à ma demande mais je m'en contenterai.
Il détecte bien (sauf erreur de ma part) toutes les variables inutilisées et seulement celles-là, avec le module de test "Module_Test" du fichier. Il tient également compte des paramètres des procédures mono ou multi-lignes (voir post précédent).
RubberDuck, seule proposition que j'ai pu testée, commet des erreurs (voir posts précédents).
En attendant mieux, je mets mon fichier comme solution.

Le contenu du fichier
  • La feuille "Variables Inutilisées"
Le bouton "Analyser Variables inutilisées" exécute la macro LancerAnalyseCodeVarInu pour analyser le module de la ligne...​
Bonsoir,
Les variables VarConnu1, VarConnu2 et VarConnu3 de la procédure Procedure_3 sont détectées comme "jamais assignée" à tort.
En êtes-vous certain ? Dans le code :
VB:
Sub Procedure_3()
    Dim Tab2() As String                         'VarInconnu0
    'Dim Tab3() As String
    Dim ItemTab1
    Dim ItemTab2
    Dim LigneCourante As String, VarInconnu1
    Dim VarConnu1
    Dim VarConnu2
    Dim VarConnu3
    Dim VarInconnu2
    Dim VarInconnu3
    Dim VarInconnu4
    'Dim VarInconnu5

    'VarInconnu2=0
    iii = 0
    LigneCourante = "xxxxxxxxxxxxxxx" & vbLf     'VarInconnu2
    LigneCourante = "xxxxxxxxxxxxxxx" & VarConnu1
    LigneCourante = "xxxxVarConnu2xxxxxxxx" & VarConnu2
    LigneCourante = "'xxxxVarConnu3xxxxxxxx" & VarConnu3
    LigneCourante = "xxxxVarInconnu2xxxxxxxx"
    LigneCourante = "xxxxVarInconnu3xxxVarInconnu3xxxxx"
    LigneCourante = "xxxxVarInconnu4xxxxxxxx" & "xxxxVarInconnu4xxxxxxxx"
    Tab1 = Filter(Split(LigneCourante, vbLf), "Dim")
    Tab2 = Filter(Split(Replace(Replace(ItemTab1, "Dim ", "Dim µ"), ", ", " µ")), "µ")
    For Each ItemTab2 In Tab2
    Next
End Sub
Vous déclarez bien VarConnu1 par exemple, mais il n'est pas affecté, et donc sera égal à Nothing. Il n'y a pas d'erreur de la part de RubberDuck. 😉
Par contre, il se plante sur la variable jjj déclarée au niveau module et aussi dans Procedure_2 où la variable iii est utilisée (mais c'est donc la locale à Procedure_2.
Là encore en êtes-vous certains ? Nous pouvons (même si ce n'est pas conseillé) déclarer un variable au niveau module et au niveau d'une procédure. Dans la procédure la variable locale prendra le pas sur celle du module, donc pas d'erreur.
Et si vous regardez bien les inspections il trouve bien la variable jjj inutilisée :

000075.png

Mais bon il y en a tellement qu'il faut bien chercher...
 
Dernière édition:
Bonsoir,

En êtes-vous certain ? Dans le code :
VB:
Sub Procedure_3()
    Dim Tab2() As String                         'VarInconnu0
    'Dim Tab3() As String
    Dim ItemTab1
    Dim ItemTab2
    Dim LigneCourante As String, VarInconnu1
    Dim VarConnu1
    Dim VarConnu2
    Dim VarConnu3
    Dim VarInconnu2
    Dim VarInconnu3
    Dim VarInconnu4
    'Dim VarInconnu5

    'VarInconnu2=0
    iii = 0
    LigneCourante = "xxxxxxxxxxxxxxx" & vbLf     'VarInconnu2
    LigneCourante = "xxxxxxxxxxxxxxx" & VarConnu1
    LigneCourante = "xxxxVarConnu2xxxxxxxx" & VarConnu2
    LigneCourante = "'xxxxVarConnu3xxxxxxxx" & VarConnu3
    LigneCourante = "xxxxVarInconnu2xxxxxxxx"
    LigneCourante = "xxxxVarInconnu3xxxVarInconnu3xxxxx"
    LigneCourante = "xxxxVarInconnu4xxxxxxxx" & "xxxxVarInconnu4xxxxxxxx"
    Tab1 = Filter(Split(LigneCourante, vbLf), "Dim")
    Tab2 = Filter(Split(Replace(Replace(ItemTab1, "Dim ", "Dim µ"), ", ", " µ")), "µ")
    For Each ItemTab2 In Tab2
    Next
End Sub
Vous déclarez bien VarConnu1 par exemple, mais il n'est pas affecté, et donc sera égal à Nothing. Il n'y a pas d'erreur de la part de RubberDuck. 😉

Là encore en êtes-vous certains ? Nous pouvons (même si ce n'est pas conseillé) déclarer un variable au niveau module et au niveau d'une procédure. Dans la procédure la variable locale prendra le pas sur celle du module, donc pas d'erreur.
Et si vous regardez bien les inspections il trouve bien la variable jjj inutilisée :

Regarde la pièce jointe 1214277
Mais bon il y en a tellement qu'il faut bien chercher...
Merci Valtrase pour cette rectification.
Erreur de débutant RubberDuck de ma part, j'avais compris que "non assignée" signifiait "non utilisée" et bien sûr je n'étais pas allé au bout de la page d'erreurs.
Et oui mon module de test est volontairement tordu... justement pour les tests.
Je relève cependant une erreur de RubberDuck:
la variable iii déclarée au niveau module est utilisée et non déclarée dans Procedure_3. Elle ne devrait pas être détectée par RubberDuck comme "non utilisée".
On peut vérifier, en exécutant la macro Procedure_3 : pas d'erreur "variable non définie" pour iii (Option Explicit au niveau du Module).
 
Bonjour à tous,
la variable iii déclarée au niveau module est utilisée et non déclarée dans Procedure_3. Elle ne devrait pas être détectée par RubberDuck comme "non utilisée".
C'est vrai celle-là il ne la voit pas. Par contre dans Lecture et facilité d'entretien il trouve bien (Restreindre la portée du champ iii) si l'on régle les problèmes dans l'ordre l'erreur disparaitra d'elle-même.

Pour finir je dirais que personne n'est parfait, et qu'il est toujours temps de remonter le bug sur la page de RubberDuck.
Je l'utilise au quotidien, en parallèle avec MZ-Tools 8 ils sont complémentaires.

Avantages de l'un et de l'autre (De mon expérience)
RubberDuck :
  • L'indentation aux petits oignons
  • Les inspections dont on vient de discuter avec toutes les possibilités de filtrage.
  • La re-factorisation, (Nommage, etc...)
  • Les outils (A faire Todo etc...)
  • La possibilité de faire des tests unitaires.
  • La visualisation en direct de l'utilisation d'une variable :
000076.png


MZ-Tools
J'utilise beaucoup d'outils de MZ-Tools entre autres pour
  • Les assistants TabIndex, Noms de contrôles, Nouvelle méthode/Propriété, Msgbox, connexion à une base de donnée.
  • Les propriétés par défaut des contrôles.
  • La bibliothèque de code
  • Les Copie vers et Depuis.
  • Le tri des modules et procédures.
  • L'échange d'assignement (A= B vers B=A)
Et j'en passe, une fois goûter aux deux il est difficile de s'en défaire.
 
Bonsoir à tous,
un dernier (?) bilan de mes tests et recherches
Merci encore Valtrase e m'avoir fait découvrir RubberDuck.
Pour ce qui concerne la recherche des variables inutilisées (mon besoin), RubberDuck n'est pas très fiable.
J'ai relevé pas mal d'erreurs avec mon fichier de test
RubberDuck détecte des variables inutilisées à tort (en rouge dans la capture d'écran du rapport.
1741726398632.png


Ci-dessous, mon fichier de test, tordu certes, mais pour passer dans le maximum de cas.
Les lignes de déclarations des variables inutilisées sont avec le commentaire VARIABLE INUTILE
Les lignes de déclarations des variables utilisées mais détectées à tort comme inutilisées par RubberDuck sont avec le commentaire KO dans RubberDuck

VB:
' Module6_PourVar
'----------------
Option Explicit
Dim xxx, yyy ',zzz ' VARIABLE INUTILE  ---> xxx , yyy
Dim Tab1() As String, sss ' VARIABLE INUTILE  ---> sss 'Tab1 KO dans RubberDuck
'Dim Tab2() As String
Dim iii ' Dim inutilisée
Dim ttt ' VARIABLE INUTILE ---> ttt
Dim jjj ' VARIABLE INUTILE
'===================================================
Sub Procedure_1()
Dim VarInu As String 'même nom que dans Procedure_2 mais inutilisé ici ' VARIABLE INUTILE ---> VarInu
    With ThisWorkbook.VBProject
    End With
End Sub
Sub Procedure_2()
    Dim VarInux As String ' VARIABLE INUTILE  ---> VarInux
    Dim VarInu As String 'même nom que dans Procedure_1 mais utilisé ici 'KO dans RubberDuck
    Dim iii As Long 'ici variable locale ' VARIABLE INUTILE ---> iii
    Dim jjj As Long 'ici variable locale 'KO dans RubberDuck
    Dim jjjx As Long 'KO dans RubberDuck
    Dim i As Long
    jjj = 0
    jjjx = 0
    VarInu = ""
    For i = 1 To 10
    Next i
End Sub
'Sub Proce_jjj_dure_3() '-> ko jjj
'Sub Procedure_3(jjj As Integer) '-> ko jjj
Sub Procedure_3()
    Dim Fo As Integer '-> (For)
    Dim Tab2() As String 'VarInconnu0
    'Dim Tab3() As String
    Dim ItemTab1
    Dim ItemTab2 'KO dans RubberDuck
    Dim LigneCourante As String, VarInconnu1 ' VARIABLE INUTILE ---> VarInconnu1
    Dim VarConnu1
    Dim VarConnu2
    Dim VarConnu3
    Dim VarInconnu2 ' VARIABLE INUTILE ---> VarInconnu2
    Dim VarInconnu3 ' VARIABLE INUTILE ---> VarInconnu3
    Dim VarInconnu4 ' VARIABLE INUTILE ---> VarInconnu4
    'Dim VarInconnu5

    'VarInconnu2=0
    iii = 0
    LigneCourante = "xxxxxxxxxxxxxxx" & vbLf 'VarInconnu2
    LigneCourante = "xxxxxxxxxxxxxxx" & VarConnu1
    LigneCourante = "xxxxVarConnu2xxxxxxxx" & VarConnu2
    LigneCourante = "'xxxxVarConnu3xxxxxxxx" & VarConnu3
    LigneCourante = "xxxxVarInconnu2xxxxxxxx"
    LigneCourante = "xxxxVarInconnu3xxxVarInconnu3xxxxx"
    LigneCourante = "xxxxVarInconnu4xxxxxxxx" & "xxxxVarInconnu4xxxxxxxx"
    Tab1 = Filter(Split(LigneCourante, vbLf), "Dim")
    Tab2 = Filter(Split(Replace(Replace(ItemTab1, "Dim ", "Dim µ"), ", ", " µ")), "µ")
    For Each ItemTab2 In Tab2
        iii = iii + 1
    Next
End Sub
Sub testiii()
    MsgBox iii
    valiii
    MsgBox iii
End Sub
Sub valiii()
    iii = 5
End Sub

J'ai continué à bricoler mon code qui ne fait pas d'erreur avec mon jeu de test.
Comme je l'ai écrit précédemment, il ne traite que les variables déclarées Dim.
Un cas que je n'ai pas (encore) traité : si un paramètre e procédure a le même nom qu'une une variable de déclaration niveau module non utilisée dans le module, elle n'est pas détectée comme variable inutilisée.

Mon code comprend
Une feuille nommée Variables Inutilisées avec 2 boutons

Macro appelée par le 1er bouton : ListerComposantsClasseurs qui liste les composants de tous les classeurs ouverts
Macro appelée par le 2ème bouton : LancerAnalyseCodeVarInu (sélectionner une ligne pour analyser le module correspondant)
Le résultat est dans la fenêtre d'exécution (Debug.Print)

1741727819943.png

Un Module
VB:
Option Explicit
Dim NomModule As String
Dim NomProc As String
Dim TypeProcedure As vbext_ProcKind
Dim LigneStartProc As Long
Dim LigneBodyProc As Long
Dim NbLignesProc As Long
Dim CodeContenu As String
Dim CodeDeclaration As String
Dim TypeDeclaration As String
Dim ListeVarInuProc As String, ListeVarInuModule As String
Dim NbInutile As Integer
Dim TabDimEc() As String, ITabDimEc As Integer
Dim TabDimEcc() As String, ITabDimEcc As Integer, ITabDimEcc2 As Integer
Dim TabDimEccVide As Boolean
Sub ListerComposantsClasseurs()
' Liste des composanst des classeurs ouverts
Dim DerLigne As Long, DerColonne As Long
Dim VBComp As VBComponent
Dim i As Integer
Dim WorkBookCourant As Workbook
    With Sheets("Variables Inutilisées")
        DerLigne = .Cells(.Rows.Count, .Range("A2").Column).End(xlUp).Row
        DerColonne = .Cells(.Range("A1").Row, .Columns.Count).End(xlToLeft).Column
        Application.EnableEvents = False
        .Range(.Range("A2"), .Cells(DerLigne, DerColonne)).ClearContents
        Application.EnableEvents = True

        i = 2
       For Each WorkBookCourant In Workbooks
           For Each VBComp In WorkBookCourant.VBProject.VBComponents
               .Cells(i, 1) = WorkBookCourant.Name
               .Cells(i, 2) = VBComp.Name
               i = i + 1
           Next VBComp
       Next WorkBookCourant
    End With
End Sub
Sub LancerAnalyseCodeVarInu()
    ' Demande d'analyse pour un module d'un Classeur OUVERT
    ' de la ligne sélectionnée dans la feuille
    With ActiveSheet
        AnalyseCodeVarInu .Cells(ActiveCell.Row, 1), .Cells(ActiveCell.Row, 2)
    End With
End Sub
Sub AnalyseCodeVarInu(pNomClasseur As String, pNomModule As String)
' Fonctionne pour les Variables déclarées Dim dans le Module
'  Il y aura besoin de code supplémentaire pour des variables :
'       Public, Private, Static, Array, Type ... End Type
Dim Titre As String
Dim Message As String
Dim Debut As Long
Dim i As Integer, j As Integer

    Titre = "Analyse des variables (Dim) inutilisées dans un Module"
   
    'On analyse uniquement les variables déclarées Dim
    TypeDeclaration = "Dim "
   
    NomModule = pNomModule
    NbInutile = 0
       
    With Workbooks(pNomClasseur).VBProject.VBComponents(NomModule).CodeModule
   
        TabDimEccVide = True
   
        'Déclarations du Module
        '----------------------
        NomProc = ""
        NbLignesProc = .CountOfDeclarationLines
        If NbLignesProc > 0 Then
            CodeDeclaration = .Lines(1, .CountOfDeclarationLines) & vbLf
            MajTableauDimProcedure CodeDeclaration
        End If
       
     
        ' Déclarations de Chaque Procédure
        '---------------------------------
        'positionnement après la partie Déclarations du Module
        Debut = .CountOfDeclarationLines + 1
        Do Until Debut >= .CountOfLines
            NomProc = .ProcOfLine(Debut, TypeProcedure)
            LigneBodyProc = .ProcBodyLine(NomProc, TypeProcedure)
            NbLignesProc = .ProcCountLines(NomProc, TypeProcedure)
            CodeContenu = .Lines(LigneBodyProc, NbLignesProc)
            MajTableauDimProcedure CodeContenu
            Debut = Debut + NbLignesProc + 1
        Loop
       

        ' liste des Variables Dim du Module (nom procédure - nom variable)
        If ITabDimEcc > 0 Then
            For ITabDimEcc = LBound(TabDimEcc, 2) To UBound(TabDimEcc, 2)
                Message = Message & TabDimEcc(0, ITabDimEcc) & " - " & TabDimEcc(1, ITabDimEcc) & vbLf
            Next ITabDimEcc
        Else
            Message = "Aucune variable déclarée !"
            MsgBox Message, vbInformation, "Liste des variables du Module" & NomModule
            GoTo FinTraitement
        End If
       
        ' Pour afficher la Liste des variables déclarées
        MsgBox Message, vbInformation, "Liste des variables du Module" & NomModule
               
        'Analyse des Déclarations du Module
        '----------------------------------
        ListeVarInuProc = ""
        NomProc = ""
        LigneStartProc = 1
        LigneBodyProc = 1
        NbLignesProc = .CountOfDeclarationLines
        If NbLignesProc > 0 Then
            CodeContenu = .Lines(1, .CountOfLines)
            AnalyseCodeVarInuProcedure True, CodeContenu
        End If

        ListeVarInuModule = "--- Déclarations du Module" & vbLf
        If ListeVarInuProc = "" Then ListeVarInuModule = ListeVarInuModule & "Aucune" Else ListeVarInuModule = ListeVarInuModule & ListeVarInuProc
       
       
        'Analyse des Déclarations de Chaque Procédure
        '--------------------------------------------
        'positionnement après la partie Déclarations du Module
        Debut = .CountOfDeclarationLines + 1
        Do Until Debut >= .CountOfLines
            ListeVarInuProc = ""
            NomProc = .ProcOfLine(Debut, TypeProcedure)
            LigneStartProc = .ProcStartLine(NomProc, TypeProcedure)
            LigneBodyProc = .ProcBodyLine(NomProc, TypeProcedure)
            NbLignesProc = .ProcCountLines(NomProc, TypeProcedure)
            CodeContenu = .Lines(LigneBodyProc, NbLignesProc)
            AnalyseCodeVarInuProcedure False, CodeContenu
            Debut = Debut + NbLignesProc + 1
           
            ListeVarInuModule = ListeVarInuModule & vbLf & "--- Déclarations de la Procédure " & NomProc & vbLf
            If ListeVarInuProc = "" Then ListeVarInuModule = ListeVarInuModule & "Aucune" Else ListeVarInuModule = ListeVarInuModule & ListeVarInuProc
        Loop
       
        ' Pour afficher la Liste des variables inutilisées dans tout le module
        'MsgBox ListeVarInuModule, vbInformation, "Liste de toutes les variables inutilisées du Module" & NomModule
        Debug.Print "-----------------------------------------------------------------------------------------------------------"
        Debug.Print "     Liste de toutes les variables inutilisées du Module" & NomModule & " du classeur " & pNomClasseur
        Debug.Print "-----------------------------------------------------------------------------------------------------------"
        Debug.Print ListeVarInuModule
       
FinTraitement:
        If ITabDimEcc > 0 Then
            Message = "Analyse du Code du Module " & pNomModule & " du classeur " & pNomClasseur & " terminée." & vbLf _
            & NbInutile & " variables inutilisées." & vbLf _
            & "Voir la fenêtre Exécution de l'éditeur VBE"
        Else
            Message = "Analyse du Code du Module " & pNomModule & " du classeur " & pNomClasseur & " terminée." & vbLf _
            & "Aucune variable déclarée !"
        End If
        MsgBox Message, vbInformation, Titre
    End With
           
End Sub
Sub MajTableauDimProcedure(pCodeDeclaration As String)

Dim TabCodeDeclaration() As String
Dim ChaineDim As String
Dim TabDim() As String, ITabDim As Integer
Dim i As Integer, j As Integer
Dim Pos As Integer

   
    ' Préparation des tableaux de déclarations Dim
    '---------------------------------------------
    TabCodeDeclaration = Split(pCodeDeclaration, vbLf)
    'la dernière ligne est vide
    ReDim Preserve TabCodeDeclaration(0 To UBound(TabCodeDeclaration) - 1)
    For i = LBound(TabCodeDeclaration) To UBound(TabCodeDeclaration)
        ' on enlève les espaces de gauche
        TabCodeDeclaration(i) = LTrim(TabCodeDeclaration(i))
        ' on enlève le saut de ligne
        If Len(TabCodeDeclaration(i)) <> 0 And i < UBound(TabCodeDeclaration) - LBound(TabCodeDeclaration) Then
            TabCodeDeclaration(i) = Left(TabCodeDeclaration(i), Len(TabCodeDeclaration(i)) - 1)
        End If
        If Left(LTrim(TabCodeDeclaration(i)), Len(TypeDeclaration)) = TypeDeclaration Then
            ' Ligne Dim
            If ChaineDim = "" Then ChaineDim = TabCodeDeclaration(i) Else ChaineDim = ChaineDim & vbLf & TabCodeDeclaration(i)
        End If
    Next i
   
    ' TabDim contient toutes les déclarations Dim : "Dim xxx"
    TabDim = Split(ChaineDim, vbLf)
   
 
    ' Contrôle du contenu à partir des tableaux de déclarations Dim
    '--------------------------------------------------------------
   
    For ITabDim = LBound(TabDim) To UBound(TabDim)
        ' ici on éclate les déclarations multiples sur la même e lignes en x lignes
        ' on élimine ce qui est en commentaire car il peut y avoir par exemple "Dim Var 1 ' Dim Var2"
        Pos = InStr(TabDim(ITabDim), "'")
        If Pos <> 0 Then
            TabDim(ITabDim) = Left(TabDim(ITabDim), Pos - 1)
        End If
        TabDimEc = Filter(Split(Replace(Replace(TabDim(ITabDim), "Dim ", "Dim µ"), ", ", " µ")), "µ")
        ITabDimEc = 0
        For i = LBound(TabDimEc) To UBound(TabDimEc)
            ITabDimEc = ITabDimEc + 1
            TabDimEc(i) = Replace(TabDimEc(i), "µ", "")
            If InStr(TabDimEc(i), "(") <> 0 Then
                ' Variable Tableau
                '   -> pour détecter l'utilisation dans le code on testera "Var(" et "Var"
                TabDimEc(i) = Left(TabDimEc(i), InStr(TabDimEc(i), "(") - 1)
            End If
        Next i
       
        If ITabDimEc > 0 Then
            'tableau TabDimEc non vide
            If TabDimEccVide Then
                ITabDimEcc = 0
                ReDim TabDimEcc(1, UBound(TabDimEc) - LBound(TabDimEc))
                TabDimEccVide = False
            Else
                ITabDimEcc = UBound(TabDimEcc, 2) + 1
                ReDim Preserve TabDimEcc(1, UBound(TabDimEcc, 2) + UBound(TabDimEc) + 1)
            End If
            For i = LBound(TabDimEc) To UBound(TabDimEc)
                TabDimEcc(0, ITabDimEcc) = NomProc
                TabDimEcc(1, ITabDimEcc) = TabDimEc(i)
                ITabDimEcc = ITabDimEcc + 1
            Next i
        End If
       
    Next ITabDim
End Sub
Sub AnalyseCodeVarInuProcedure(pDeclarationModule As Boolean, pCodeContenu As String)
Dim TabCodeContenu() As String
Dim TabDim() As String, ITabDim As Integer
Dim ChaineSansCom As String
Dim TabSansCom() As String, ITabSansCom As Integer
Dim i As Integer
Dim ChaineW As String
Dim Pos As Integer, Pos2 As Integer
Dim Absent As Boolean
Dim TrouveMot As Boolean
Dim LigneProcedureCourante As String
Dim NbOcc As Integer
Dim Fin As Boolean

    ' Analyse variables (pour le moment seulement Dim)
    '-------------------
   
    ' Tableau du contenu sans Dim et sans les lignes commentaires
    '---------------------------------------------
    ChaineSansCom = ""
    TabCodeContenu = Split(pCodeContenu, vbLf)
    For i = LBound(TabCodeContenu) To UBound(TabCodeContenu)
        If Len(TabCodeContenu(i)) <> 0 And i <> UBound(TabCodeContenu) Then TabCodeContenu(i) = Left(TabCodeContenu(i), Len(TabCodeContenu(i)) - 1)
        If Left(LTrim(TabCodeContenu(i)), Len(TypeDeclaration)) <> TypeDeclaration Then
            If Left(LTrim(TabCodeContenu(i)), 1) <> "'" Then
                If ChaineSansCom = "" Then ChaineSansCom = TabCodeContenu(i) Else ChaineSansCom = ChaineSansCom & vbLf & TabCodeContenu(i)
            End If
        End If
    Next i
    ' élimination des lignes commentaires
    TabSansCom = Split(ChaineSansCom, vbLf)
   
    ' Contrôle du contenu à partir du tableau de déclarations Dim
    '--------------------------------------------------------------
    LigneProcedureCourante = ""
    ' liste des Variables Dim du Module (nom procédure - nom variable
    For ITabDimEcc = LBound(TabDimEcc, 2) To UBound(TabDimEcc, 2)
        'on ne considère que les variables déclarées dans la procédure courante (NomProc ="" pour les déclarations de niveau module
        If TabDimEcc(0, ITabDimEcc) = NomProc Then
            Absent = True
            For ITabSansCom = LBound(TabSansCom) To UBound(TabSansCom)
                If pDeclarationModule Then
                    'on mémorise le nom de la procédure courante
                    ChaineW = MemoProcCourante(LTrim(TabSansCom(ITabSansCom)))
                    If ChaineW <> "" Then LigneProcedureCourante = ChaineW
                End If
               
                ' Recherche de toutes les occurences de présence de la variable courante dans la ligne de code courante
                ' On examine toutes les coccurrences jusqu'à ce que une soit correcte
                '   - Pas en commentaire
                '   - Pas encadrée par ""
                Pos = InStr(TabSansCom(ITabSansCom), TabDimEcc(1, ITabDimEcc))
                If Pos = 0 Then
                    Fin = True
                Else
                    ChaineW = TabSansCom(ITabSansCom)
                    Fin = False
                End If
                While Not Fin
                    If EstMot(ChaineW, TabDimEcc(1, ITabDimEcc), Pos) Then
                        ' Pos contient la position de la variable dans la ligne courante
                        ' on regarde si trouvé en dehors d'une zone commentaire
                        ChaineW = Mid(ChaineW, Pos, Len(ChaineW))
                        Pos2 = InStr(ChaineW, "'")
                        If Pos2 <> 0 Then
                            ' on a trouvé le caractère ' sur la ligne
                            If ChaineEntreApostrophes(ChaineW, "'") Then
                                'le caractère ' est encadré par "" -> ce n'est donc pas commentaire
                                'on regarde si variable encadré par ""
                                Absent = ChaineEntreApostrophes(ChaineW, TabDimEcc(1, ITabDimEcc))
                                '''If Not Absent Then Exit For
                            End If
                        Else
                            'pas dans zone commentaire
                            'on regarde si encadré par ""
                            Absent = ChaineEntreApostrophes(ChaineW, TabDimEcc(1, ITabDimEcc))

                        End If
                        If Absent Then
                            'on cherche l'occurence suivante dans la ligne
                            ChaineW = Mid(ChaineW, Pos, Len(ChaineW))
                            If ChaineW = "" Then Fin = True
                        Else
                            Fin = True
                        End If
                    Else
                        Fin = True
                    End If
                       
                Wend
                If Not Absent Then
                    If Not pDeclarationModule Then
                        Exit For
                    Else
                        ' Variable de Niveau Module
                        ' La variable est utilisée dans une procédure mais il faut vérifier qu'elle n'est pas aussi déclarée dans la procédure
                        For ITabDimEcc2 = LBound(TabDimEcc, 2) To UBound(TabDimEcc, 2)
                            If LigneProcedureCourante <> "" _
                            And (TabDimEcc(0, ITabDimEcc2) = LigneProcedureCourante) _
                            And (TabDimEcc(1, ITabDimEcc2) = TabDimEcc(1, ITabDimEcc)) Then
                                ' La variable est utilisée dans la procédure mais elle est aussi déclarée dans la procédure
                                Absent = True
                            End If
                        Next ITabDimEcc2
                        If Not Absent Then Exit For
                    End If
                End If

            Next ITabSansCom
            If Absent Then
                NbInutile = NbInutile + 1
                ' pour le Debug.Print
                If ListeVarInuProc = "" Then ListeVarInuProc = ListeVarInuProc & TabDimEcc(1, ITabDimEcc) Else ListeVarInuProc = ListeVarInuProc & vbLf & TabDimEcc(1, ITabDimEcc)
            End If
        End If
   
    Next ITabDimEcc

End Sub
Function MemoProcCourante(Pchaine As String) As String

    MemoProcCourante = ""
    Select Case True
        Case Pchaine Like "Private Sub*"
            MemoProcCourante = Mid(Pchaine, Len("Private Sub*") + 1)
            MemoProcCourante = Left(MemoProcCourante, InStr(MemoProcCourante, "(") - 1)
        Case Pchaine Like "Private Function*"
            MemoProcCourante = Mid(Pchaine, Len("Private Function*") + 1)
            MemoProcCourante = Left(MemoProcCourante, InStr(MemoProcCourante, "(") - 1)
        Case Pchaine Like "Sub*"
            MemoProcCourante = Mid(Pchaine, Len("Sub*") + 1)
            MemoProcCourante = Left(MemoProcCourante, InStr(MemoProcCourante, "(") - 1)
        Case Pchaine Like "Function*"
            MemoProcCourante = Mid(Pchaine, Len("Function*") + 1)
            MemoProcCourante = Left(MemoProcCourante, InStr(MemoProcCourante, "(") - 1)
           
    End Select
End Function
Function ChaineEntreApostrophes(Pchaine As String, pRech As String) As Boolean
    'on regarde si encadré par ""
    Dim ChaineW As String
    Dim Pos As Long, Pos2 As Long
    Dim Absent As Boolean
    Dim Fin As Boolean

    ChaineEntreApostrophes = True
   
    Pos = InStr(Pchaine, pRech)
    Pos2 = InStr(Pchaine, """")
    If Pos2 < Pos Then
        ' le premier " est situé avant, on va regarder où est le suivant
        ChaineW = Mid(Pchaine, Pos2 + 1, Len(Pchaine))
        Fin = False
        While Not Fin
            Pos = InStr(ChaineW, pRech)
            Pos2 = InStr(ChaineW, """")
            Select Case True
                Case Pos = 0
                    ' Var non trouvée hors zone commentaire
                    Fin = True
                Case Pos2 = 0 And Pos <> 0
                    ' pas de 2ème "
                    ChaineEntreApostrophes = False
                    Fin = True
                Case Else
                    ' 2ème " avant ou après la variable -> on avance
                    ChaineW = Mid(ChaineW, Pos2 + 1, Len(ChaineW))
            End Select
        Wend
    Else
        ChaineEntreApostrophes = False
    End If
End Function

Function EstMot(Pchaine As String, pRech As String, ByRef pPosMot As Integer)
' pPosMot contient la position du MOT pRech trouvé dans pChaine
'''Const SEPARATEUR = " [.!#$%&'*/=?^_`{|} ~+-]"
Const SEPARATEUR = " ,()"
Dim i As Integer
Dim Pos As Integer, PosSuiv As Integer
Dim Fin As Boolean
Dim ChaineW As String
Dim AvantOk As Boolean
 
    EstMot = False
    ChaineW = Pchaine
    pPosMot = 0
    Fin = False
    While Not Fin
        Pos = InStr(ChaineW, pRech)
        PosSuiv = Pos + Len(pRech)
        AvantOk = False
        Select Case Pos
            Case 0
                Fin = True
            Case 1
                'pas de caractère précédent
                AvantOk = True
            Case Else
                For i = 1 To Len(SEPARATEUR)
                    If Mid(ChaineW, Pos - 1, 1) = Mid(SEPARATEUR, i, 1) Then
                        'Caractère précédent est un signe de mot
                        AvantOk = True
                        Exit For
                    End If
                Next i
        End Select
        If AvantOk Then
            If PosSuiv > Len(ChaineW) Then
                EstMot = True
            Else
                For i = 1 To Len(SEPARATEUR)
                    If Mid(ChaineW, PosSuiv, 1) = Mid(SEPARATEUR, i, 1) Then
                        'Caractère suivant est un signe de mot
                        EstMot = True
                        Exit For
                    End If
                Next i
            End If
        End If
        If Not EstMot Then
            ChaineW = Mid(ChaineW, PosSuiv, Len(ChaineW))
            pPosMot = pPosMot + PosSuiv - 1
            If ChaineW = "" Then Fin = True
        Else
            pPosMot = pPosMot + PosSuiv - Len(pRech)
            Fin = True
        End If
    Wend
    If Not EstMot Then pPosMot = 0
End Function

Merci à ceux qui prendraient le temps de tester mon code de me faire un retour.
 
Dernière édition:
Bonsoir,

en pj mon fichier de bricolage.

[EDIT du 13/03] : Il ne répond pas totalement à ma demande mais je m'en contenterai.
Il détecte bien (sauf erreur de ma part) toutes les variables inutilisées et seulement celles-là, avec le module de test "Module_Test" du fichier. Il tient également compte des paramètres des procédures mono ou multi-lignes (voir post précédent).
RubberDuck, seule proposition que j'ai pu testée, commet des erreurs (voir posts précédents).
En attendant mieux, je mets mon fichier comme solution.

Le contenu du fichier
  • La feuille "Variables Inutilisées"
Le bouton "Analyser Variables inutilisées" exécute la macro LancerAnalyseCodeVarInu pour analyser le module de la ligne sélectionnée dans le tableau.​
Le résultat est dans la fenêtre d'exécution de l'éditeur VBE, ce qui permet de nettoyer le code du Module traité plus facilement.​
  • Le Module "Module_Varinu" qui contient l'ensemble des macros.
  • Le Module de test "Module_Test".
1741816748732.png
 

Pièces jointes

Dernière édition:
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

L
Réponses
6
Affichages
6 K
Ludo-ly
L
Retour