Accueil/Docs/PRQL & Code Query/Maîtriser la syntaxe PRQL avec CppDepend

Maîtriser la syntaxe PRQL avec CppDepend

Maîtriser la syntaxe PRQL avec CppDepend

Ce document suppose que vous êtes familier avec Syntaxe LINQ, et expose les particularités de la syntaxe PRQL.

PRQL, Code Query LINQ, est une fonctionnalité proposée par l'outil CppDepend depuis la version 3, pour interroger le code C/C++ via des requêtes LINQ.

Vidéo de démarrage

Une courte vidéo de 1:50 minute présentant la syntaxe PRQL est disponible sur le site de documentation CppDepend.

Édition de requêtes PRQL

Une requête PRQL peut être éditée en direct dans l'UI CppDepend (autonome ou dans Visual Studio).

Éditeur de requêtes PRQL

La requête s'exécute automatiquement dès qu'elle compile.

Notez dans la capture d’écran ci-dessus 13 ms en haut à droite, qui indique la durée d'exécution de la requête.

PRQL est rapide et conçu pour exécuter des centaines de requêtes par seconde sur une grande base de code réelle.

L’édition PRQL est également fournie avec complétion de code/IntelliSense, et aussi documentation des info-bulles au survol du corps de la requête.

Domaines prédéfinis

PRQL définit quelques domaines prédéfinis à interroger, notamment : Types ; Méthodes ; Champs ; Espaces de noms ; Projets

Ces domaines énumèrent non seulement tous les éléments de code de la base interrogée, mais aussi tous tiers éléments de code utilisés par la base de code (comme par exemple le type string et toutes les méthodes et champs du type string utilisés par la base de code).

La syntaxe est aussi simple que :

1from m in Methods where m.NbLinesOfCode > 30 select m

Une requête PRQL peut s'appuyer sur un ou plusieurs domaines. Remarquez dans la requête ci-dessus comment le mot de domaine Méthodes est mis en évidence différemment.

Il existe deux domaines prédéfinis pratiques souvent utilisés : Application et ThirdParty. Comme leur nom l'indique, ces domaines sont utiles pour énumérer les éléments de code définis uniquement dans les projets d'application, ou définis uniquement dans les projets tiers (comme STL, MFC ou Boost) et utilisés par le code de l'application. Ces deux domaines représentent chacun une vue partielle de l'ensemble de la base de code.

1from m in Application.Methods where m.NbLinesOfCode > 30 select m

Il est facile d’affiner ces domaines prédéfinis.

Par exemple, la requête ci-dessous correspond aux grandes méthodes définies uniquement dans l’espace de noms ProductName.FeatureA et ses espaces de noms enfants :

1from m in Application.Namespaces.WithNameLike("ProductName.FeatureA").ChildMethods()
2where m.CyclomaticComplexity > 10 select m

Définition de la vue de base de code JustMyCode avec le préfixe notmycode

Il existe un autre domaine prédéfini pratique nommé JustMyCode.

Le domaine JustMyCode représente une fonctionnalité de PRQL pour éliminer les éléments de code générés des résultats de requête PRQL.

Par exemple, la requête suivante ne correspond qu'aux grandes méthodes qui ne sont pas générées par un outil (comme un concepteur d'UI) :

1from m in JustMyCode.Methods where m.NbLinesOfCode > 30 select m

L'ensemble des éléments de code générés est défini par des requêtes PRQL préfixées par le mot-clé PRQL notmycode.

Par exemple, la requête ci-dessous correspond aux méthodes définies dans des fichiers sources dont le nom contient un mot spécifique.

1notmycode from m in Methods where
2
3 m.SourceFileDeclAvailable &&
4
5 m.SourceDecls.First().SourceFile.FileName.ToLower().Contains("generated.cpp")
6
7select m

L’exécuteur de requêtes PRQL exécute toutes notmycode requêtes avant les requêtes s’appuyant sur JustMyCode, d’où le domaine JustMyCode est défini une fois pour toutes. Évidemment, le compilateur PRQL émet une erreur si notmycode requête s’appuie sur le JustMyCode domaine.

Règles de code PRQL

Une requête PRQL peut être facilement transformée en règle en la préfixant d'une condition définie avec les deux mots-clés PRQL nombre warnif.

Le mot-clé count est un entier non signé égal au nombre d'éléments de code correspondant à la requête.

Par exemple, la requête suivante avertit si de grandes méthodes sont trouvées parmi les méthodes de l'application :

1// <Name>Avoid too large methods</Name>
2
3warnif count > 0
4
5from m in Application.Methods
6
7where m.NbLinesOfCode > 30
8
9select m
Balise Warn dans l’éditeur de requêtes

Les règles de code PRQL sont utiles pour définir les mauvaises pratiques que l'équipe veut éviter dans la base de code.

L'équipe peut voir les avertissements de violation des règles de code dans l'UI CppDepend (autonome ou dans Visual Studio), ou dans le rapport.

L'équipe a aussi la possibilité de définir certaines règles comme règles critiques.

Les syntaxes d'opérateur de requête et d'expression de requête

Avec PRQL, la syntaxe d'opérateur de requête et la syntaxe d'expression de requête sont toutes deux autorisées.

La syntaxe d'opérateur de requête est celle avec des appels directs à des méthodes comme Where() et Select()...

1Methods.Where(m => m.NbLinesOfCode > 30)

La syntaxe des expressions de requête comprend des mots-clés comme where et sélectionner...

1from m in Methods where m.NbLinesOfCode > 30 select m

Il est souvent pratique de mélanger les deux syntaxes dans une même requête.

  • La syntaxe d'opérateur de requête est pratique pour définir des sous-ensembles et sous-domaines.
  • La syntaxe d'expression de requête est pratique pour définir des opérations sur ces sous-ensembles et sous-domaines.

Par exemple, la requête ci-dessous définit avec la syntaxe des opérateurs de requête le sous-ensemble des méthodes définies dans les types statiques, et utilise la syntaxe des expressions de requête pour filtrer et projeter les grandes méthodes de ce sous-ensemble.

1from m in Application.Types.Where(t => t.IsNested).ChildMethods()
2where m.NbLinesOfCode > 30 select m

Définir des variables de portée avec let

La syntaxe LINQ offre la possibilité de définir des variables de portée avec le mot-clé laisser Dans cette section, nous voulions souligner cette possibilité car l'utilisation de laisser mot-clé est une pratique courante lors de l'écriture de requêtes PRQL.

Par exemple, la règle par défaut suivante définit une métrique de code personnalisée grâce à plusieurs variables de portée :

1// <Name>C.R.A.P method code metric</Name>
2
3// Change Risk Analyzer and Predictor (i.e. CRAP) code metric
4
5// This code metric helps in pinpointing overly complex and untested code.
6
7// Formula: CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)
8
9warnif count > 0
10
11from m in JustMyCode.Methods
12
13// Don&apos;t match too short methods
14
15where m.NbLinesOfCode > 10
16
17let CC = m.CyclomaticComplexity
18
19let uncov = (100 - m.PercentageCoverage) / 100f
20
21let CRAP = (CC * CC * uncov * uncov * uncov) + CC
22
23where CRAP != null && CRAP > 30
24
25orderby CRAP descending, m.NbLinesOfCode descending
26
27select new { m, CRAP, CC, uncoveredPercentage = uncov*100, m.NbLinesOfCode }

Notez que l’utilisation de nombreux laisser clauses dans la boucle principale de la requête peut réduire significativement les performances d'exécution de la requête.

Commencer une requête par let

Le compilateur PRQL étend l'utilisation de LINQ laisser mot-clé, car avec PRQL, le laisser mot-clé peut servir à définir une variable au début d'une requête PRQL.

Par exemple, la règle PRQL par défaut ci-dessous essaie d'abord de faire correspondre BaseClass types, et si trouvé, exécutez ensuite la requête.

1warnif count > 0
2
3let base = ThirdParty.Types.WithFullName("BaseClass").FirstOrDefault()
4
5where base != null // base can be null if the code base doesn&apos;t use at all BaseClass
6
7from t in Application.Types where
8
9 !t.DeriveFrom(base) select t

Pour certaines autres règles PRQL, il peut être pratique de définir plusieurs sous-ensembles via plusieurs laisser expressions de mots-clés, avant d'exécuter la requête elle-même.

Par exemple, les règles PRQL par défaut ci-dessous définissent d'abord les sous-ensembles uiTypes et dbTypes avant de les utiliser dans le code de la requête.

1// <Name>UI layer shouldn&apos;t use directly DB types</Name>
2
3warnif count > 0
4
5// UI layer is made of types in namespaces using a UI framework
6
7let uiTypes = Application.Namespaces.UsingAny(
8
9 Projects.WithNameIn("PresentationFramework", "MFC")
10
11 ).ChildTypes()
12
13// You can easily customize this line to define what are DB types.
14
15let dbTypes = ThirdParty.Assemblies.WithNameIn("Data").ChildTypes()
16
17 .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))
18
19from uiType in uiTypes.UsingAny(dbTypes)
20
21let dbTypesUsed = dbTypes.Intersect(uiType.TypesUsed)
22
23select new { uiType, dbTypesUsed }

Définir une procédure dans une requête

Avec la syntaxe LINQ, il est possible de créer une procédure dans une requête. Cela est utile si vous souhaitez invoquer cette procédure depuis différents endroits de la requête.

Cette possibilité est illustrée dans la règle par défaut ci-dessous, où la procédure pour vérifier si un type peut être considéré comme un type mort は 2 つの異なる場所から呼び出す必要があります:

1// <Name>Potentially dead Types</Name>
2
3warnif count > 0
4
5// Filter procedure for types that shouldn&apos;t be considered as dead
6
7let canTypeBeConsideredAsDeadProc = new Func<IType, bool>(
8
9 t => !t.IsPublic && // Public types might be used by client applications of your assemblies.
10
11 t.Name != "ClassToExclude"
12
13// Select types unused
14
15let typesUnused =
16
17 from t in JustMyCode.Types where
18
19 t.NbTypesUsingMe == 0 && canTypeBeConsideredAsDeadProc(t)
20
21 select t
22
23// Dead types = types used only by unused types (recursive)
24
25let deadTypesMetric = typesUnused.FillIterative(
26
27types => from t in codeBase.Application.Types.UsedByAny(types).Except(types)
28
29 where canTypeBeConsideredAsDeadProc(t) &&
30
31 t.TypesUsingMe.Intersect(types).Count() == t.NbTypesUsingMe
32
33 select t)
34
35from t in deadTypesMetric.DefinitionDomain
36
37select new { t, t.TypesUsingMe, depth = deadTypesMetric[t] }

Essayez CppDepend aujourd'hui

Commencez votre essai gratuit de 14 jours avec accès complet à toutes les fonctionnalités de documentation. Sans carte bancaire.