Startseite/Dokumentation/PRQL & Code-Abfrage/PRQL-Syntax mit CppDepend meistern

PRQL-Syntax mit CppDepend meistern

PRQL-Syntax mit CppDepend meistern

Dieses Dokument setzt voraus, dass Sie mit LINQ-Syntax, und zeigt die Besonderheiten der PRQL-Syntax.

PRQL, Code Query LINQ, ist eine Funktion des Tools CppDepend seit Version 3, um C/C++-Code über LINQ-Abfragen abzufragen.

Erste-Schritte-Video

Ein kurzes 1:50-minütiges Video zur PRQL-Syntax ist auf der CppDepend-Dokumentationsseite verfügbar.

PRQL-Abfragebearbeitung

Eine PRQL-Abfrage kann live in der CppDepend-UI bearbeitet werden (standalone oder in Visual Studio).

PRQL-Abfrageeditor

Die Abfrage wird automatisch ausgeführt, sobald sie kompiliert.

Beachten Sie im obigen Screenshot 13 ms oben rechts, das die Ausführungsdauer der Abfrage anzeigt.

PRQL ist schnell und dafür ausgelegt, Hunderte Abfragen pro Sekunde gegen eine große reale Codebasis auszuführen.

Die PRQL-Edition bietet außerdem Codevervollständigung/IntelliSense, und auch Tooltip-Dokumentation bei Mausbewegung über den Abfragekörper.

Vordefinierte Domänen

PRQL definiert einige vordefinierte Domänen für Abfragen, darunter: Typen ; Methoden ; Felder ; Namespaces ; Projekte

Diese Domänen zählen nicht nur alle Code-Elemente der abgefragten Codebasis auf, sondern auch alle Drittanbieter Code-Elemente, die von der Codebasis verwendet werden (wie zum Beispiel der Typ string und alle Methoden und Felder des Typs string die von der Codebasis verwendet werden).

Die Syntax ist so einfach wie:

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

Eine PRQL-Abfrage kann sich auf eine oder mehrere Domänen stützen. Beachten Sie in der obigen Abfrage, wie das Domänenwort Methoden wird anders hervorgehoben.

Es gibt zwei praktische vordefinierte Domänen, die häufig verwendet werden: Anwendung und ThirdParty. Wie ihre Namen vermuten lassen, sind diese Domänen nützlich, um Codeelemente aufzuzählen, die nur in Anwendungsprojekten definiert sind, oder solche, die nur in Drittanbieterprojekten definiert sind (wie STL, MFC oder Boost) und vom Anwendungscode verwendet. Diese beiden Domänen repräsentieren jeweils eine Teilansicht der gesamten Codebasis.

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

Es ist einfach, diese vordefinierten Domänen zu verfeinern.

Zum Beispiel matcht die folgende Abfrage große Methoden, die nur im Namespace ProductName.FeatureA und seine untergeordneten Namespaces:

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

Definition der Code-Basis-Ansicht JustMyCode mit dem Präfix notmycode

Es gibt eine weitere praktische vordefinierte Domäne namens JustMyCode.

Die Domäne JustMyCode stellt eine PRQL-Funktion dar, um generierte Code-Elemente aus PRQL-Abfrageergebnissen zu eliminieren.

Zum Beispiel matcht die folgende Abfrage nur große Methoden, die nicht von einem Tool generiert wurden (etwa einem UI-Designer):

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

Die Menge der generierten Code-Elemente wird durch PRQL-Abfragen definiert, die mit dem PRQL-Schlüsselwort notmycode.

Zum Beispiel matcht die folgende Abfrage Methoden, die in Quelldateien definiert sind, deren Name ein bestimmtes Wort enthält.

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

Der PRQL-Abfrage-Runner führt alle aus notmycode Abfragen vor Abfragen, die sich stützen auf JustMyCode, daher die Domäne JustMyCode wird ein für alle Mal definiert. Offensichtlich gibt der PRQL-Compiler einen Fehler aus, wenn notmycode Abfrage stützt sich auf JustMyCode Domäne.

PRQL-Coderegeln

Eine PRQL-Abfrage kann leicht in eine Regel umgewandelt werden, indem man ihr eine Bedingung voranstellt, die mit den beiden PRQL-Schlüsselwörtern warnif-Anzahl.

Das Schlüsselwort count ist eine vorzeichenlose Ganzzahl gleich der Anzahl der von der Abfrage gematchten Code-Elemente.

Zum Beispiel warnt die folgende Abfrage, wenn unter den Anwendungsmethoden der Codebasis große Methoden gematcht werden:

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
Warn-Tag im Abfrageeditor

PRQL-Code-Regeln sind nützlich, um festzulegen, welche schlechten Praktiken das Team in der Codebasis vermeiden will.

Das Team kann Code-Regel-Verletzungswarnungen in der CppDepend-UI (standalone oder in Visual Studio) sehen, oder im Bericht.

Das Team hat außerdem die Möglichkeit, einige Regeln als kritische Regeln.

Die Syntaxen Query-Operator und Query-Ausdruck

Mit PRQL sind sowohl die Abfrageoperator-Syntax als auch die Abfrageausdrucks-Syntax erlaubt.

Die Abfrageoperator-Syntax ist die mit direkten Aufrufen von Methoden wie Where() und Select()...

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

Die Syntax der Abfrageausdrücke umfasst Schlüsselwörter wie where und auswählen...

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

Oft ist es praktisch, beide Syntaxen in einer Abfrage zu mischen.

  • Die Abfrageoperator-Syntax eignet sich gut zum Definieren von Teilmengen und Sub-Domänen.
  • Die Abfrageausdrucks-Syntax eignet sich gut, um Operationen auf diesen Teilmengen und Sub-Domänen zu definieren.

Die Abfrage unten definiert beispielsweise mit der Abfrageoperatorsyntax die Teilmenge der in statischen Typen definierten Methoden und verwendet die Abfrageausdruckssyntax, um die großen Methoden aus dieser Teilmenge zu filtern und zu projizieren.

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

Definieren von Bereichsvariablen mit let

Die LINQ-Syntax bietet die Möglichkeit, Bereichsvariablen mit dem Schlüsselwort lassen In diesem Abschnitt wollten wir diese Möglichkeit hervorheben, denn die Verwendung von lassen Schlüsselwort ist eine gängige Praxis beim Schreiben von PRQL-Abfragen.

Zum Beispiel definiert die folgende Standardregel eine benutzerdefinierte Code-Metrik mithilfe mehrerer Bereichsvariablen:

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 }

Beachten Sie, dass die Verwendung vieler lassen Klauseln in der Hauptabfrageschleife kann die Ausführungsperformance der Abfrage deutlich verringern.

Beginn einer Abfrage mit let

Der PRQL-Compiler erweitert die Verwendung von LINQ lassen Schlüsselwort, denn mit PRQL kann lassen Schlüsselwort kann verwendet werden, um am Anfang einer PRQL-Abfrage eine Variable zu definieren.

Zum Beispiel versucht die folgende PRQL-Standardregel zunächst, BaseClass Typen, und falls gefunden, lassen Sie zweitens die Abfrage ausführen.

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

Für einige andere PRQL-Regeln kann es praktisch sein, mehrere Teilmengen über mehrere lassen Schlüsselwortausdrücke, bevor die Abfrage selbst ausgeführt wird.

Zum Beispiel definieren die folgenden PRQL-Standardregeln zunächst die Teilmengen uiTypes und dbTypes bevor Sie sie im Abfragecode verwenden.

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 }

Definieren einer Prozedur in einer Abfrage

Mit der LINQ-Syntax ist es möglich, eine Prozedur in einer Abfrage zu erstellen. Dies ist nützlich, wenn Sie eine solche Prozedur von verschiedenen Stellen in der Abfrage aufrufen möchten.

Diese Möglichkeit wird in der folgenden Standardregel veranschaulicht, in der das Verfahren zur Prüfung, ob ein Typ kann als toter Typ betrachtet werden muss von zwei verschiedenen Orten aus aufgerufen werden:

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] }

Testen Sie CppDepend noch heute

Starten Sie Ihre 14-tägige kostenlose Testversion mit vollem Zugriff auf alle Dokumentationsfunktionen. Keine Kreditkarte erforderlich.