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).

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 where23 m.SourceFileDeclAvailable &&45 m.SourceDecls.First().SourceFile.FileName.ToLower().Contains("generated.cpp")67select 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>23warnif count > 045from m in Application.Methods67where m.NbLinesOfCode > 3089select m

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>23// Change Risk Analyzer and Predictor (i.e. CRAP) code metric45// This code metric helps in pinpointing overly complex and untested code.67// Formula: CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)89warnif count > 01011from m in JustMyCode.Methods1213// Don't match too short methods1415where m.NbLinesOfCode > 101617let CC = m.CyclomaticComplexity1819let uncov = (100 - m.PercentageCoverage) / 100f2021let CRAP = (CC * CC * uncov * uncov * uncov) + CC2223where CRAP != null && CRAP > 302425orderby CRAP descending, m.NbLinesOfCode descending2627select 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 > 023let base = ThirdParty.Types.WithFullName("BaseClass").FirstOrDefault()45where base != null // base can be null if the code base doesn't use at all BaseClass67from t in Application.Types where89 !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't use directly DB types</Name>23warnif count > 045// UI layer is made of types in namespaces using a UI framework67let uiTypes = Application.Namespaces.UsingAny(89 Projects.WithNameIn("PresentationFramework", "MFC")1011 ).ChildTypes()1213// You can easily customize this line to define what are DB types.1415let dbTypes = ThirdParty.Assemblies.WithNameIn("Data").ChildTypes()1617 .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))1819from uiType in uiTypes.UsingAny(dbTypes)2021let dbTypesUsed = dbTypes.Intersect(uiType.TypesUsed)2223select 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>23warnif count > 045// Filter procedure for types that shouldn't be considered as dead67let canTypeBeConsideredAsDeadProc = new Func<IType, bool>(89 t => !t.IsPublic && // Public types might be used by client applications of your assemblies.1011 t.Name != "ClassToExclude"1213// Select types unused1415let typesUnused =1617 from t in JustMyCode.Types where1819 t.NbTypesUsingMe == 0 && canTypeBeConsideredAsDeadProc(t)2021 select t2223// Dead types = types used only by unused types (recursive)2425let deadTypesMetric = typesUnused.FillIterative(2627types => from t in codeBase.Application.Types.UsedByAny(types).Except(types)2829 where canTypeBeConsideredAsDeadProc(t) &&3031 t.TypesUsingMe.Intersect(types).Count() == t.NbTypesUsingMe3233 select t)3435from t in deadTypesMetric.DefinitionDomain3637select 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.
