ホーム/ドキュメント/PRQLとコードクエリ/CppDependでPRQL構文をマスター

CppDependでPRQL構文をマスター

CppDependでPRQL構文をマスター

このドキュメントは、読者が次に精通していることを前提としています LINQ構文、PRQL構文の特徴を示します。

PRQL(Code Query LINQ)は、バージョン 3 以降の CppDepend ツールが提供する機能で、LINQ クエリを通じて C/C++ コードをクエリします。

入門ビデオ

PRQL 構文を紹介する 1 分 50 秒の短いビデオが、CppDepend ドキュメント サイトで公開されています。

PRQLクエリ編集

PRQL クエリは、CppDepend UI(スタンドアロンまたは Visual Studio 内)でライブ編集できます。

PRQLクエリエディタ

クエリはコンパイルされるとすぐに自動実行されます。

上のスクリーンショットに注目 13ミリ秒 右上に、クエリの実行時間を示します。

PRQL は高速で、大規模な実際のコード ベースに対して 1 秒間に数百のクエリを実行するように設計されています。

PRQLエディションにはも付属 コード補完/IntelliSense、そして ツールチップドキュメント クエリ本体にマウスホバーで。

定義済みドメイン

PRQL は、次を含むいくつかの事前定義ドメインを定義します: ; メソッド ; フィールド ; 名前空間 ; プロジェクト

これらのドメインは、クエリ対象のコード ベースのすべてのコード要素だけでなく、次のすべても列挙します サードパーティ コード ベースで使用されるコード要素(たとえば型 string とその型のすべてのメソッドとフィールド string コードベースで使用されるもの)。

構文は次のようにシンプル:

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

PRQL クエリは 1 つまたは複数のドメインに依存できます。上のクエリで、ドメイン語がどのように メソッド 異なる強調表示。

よく使用される便利な事前定義ドメインが 2 つあります: アプリケーションThirdParty。名前が示すように、これらのドメインは、アプリケーションプロジェクトでのみ定義されたコード要素、またはサードパーティプロジェクトでのみ定義されたコード要素(例: STL, MFC または Boost) アプリケーション コードによって使用されます。これら 2 つのドメインは、それぞれコード ベース全体の部分的なビューを表します。

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

これらの定義済みドメインの絞り込みは簡単です。

たとえば、次のクエリは、定義された大きなメソッドに一致します のみ 名前空間内 ProductName.FeatureA とその子名前空間:

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

notmycode プレフィックスによるコード ベース ビュー JustMyCode の定義

もう 1 つの便利な事前定義ドメインがあります JustMyCode.

ドメイン JustMyCode は、PRQL クエリ結果から生成されたコード要素を除外する PRQL の機能を表します。

たとえば、次のクエリは、ツール(UI デザイナーなど)によって生成されていない大きなメソッドのみに一致します:

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

生成されたコード要素のセットは、PRQL キーワードで始まる PRQL クエリによって定義されます notmycode.

たとえば、次のクエリは、名前に特定の単語を含むソース ファイルで定義されたメソッドに一致します。

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

PRQLクエリランナーはすべてを実行 notmycode に依存するクエリの前のクエリ JustMyCode、よってドメイン JustMyCode は一度だけ定義されます。当然、次の場合 PRQL コンパイラはエラーを出力します notmycode クエリはに依存 JustMyCode ドメイン。

PRQLコードルール

PRQL クエリは、2 つの PRQL キーワードで定義された条件を先頭に付けることで、簡単にルールに変換できます warnifカウント.

キーワード count は、クエリに一致したコード要素の数に等しい符号なし整数です。

たとえば、次のクエリは、コード ベースのアプリケーション メソッドで大きなメソッドが一致した場合に警告します:

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
クエリエディタの警告タグ

PRQL コード ルールは、チームがコード ベースで避けたい悪いプラクティスを定義するのに役立ちます。

チームは、CppDepend UI(スタンドアロンまたは Visual Studio 内)でコード ルール違反の警告を確認できます。また レポート内.

チームは一部のルールを次のように定義することもできます 重大ルール.

クエリ演算子とクエリ式の構文

PRQL では、クエリ演算子構文とクエリ式構文の両方が使用できます。

クエリ演算子構文は、次のようなメソッドを直接呼び出す構文です Where()Select()...

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

クエリ式の構文には次のようなキーワードがあります where選択...

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

多くの場合、1 つのクエリで両方の構文を混在させると便利です。

  • クエリ演算子構文は、サブセットやサブドメインを定義するのに便利です。
  • クエリ式構文は、これらのサブセットやサブドメインに対する操作を定義するのに便利です。

たとえば、以下のクエリは、クエリ演算子構文で静的型に定義されたメソッドのサブセットを定義し、クエリ式構文を使用してこのサブセットから大きなメソッドをフィルタリングおよび射影します。

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

letで範囲変数を定義

LINQ 構文では、キーワードを使用して範囲変数を定義できます させる このセクションでは、この可能性を強調したいと思います。次を使用すると させる キーワードは、PRQL クエリを記述する際の一般的な手法です。

たとえば、次のデフォルト ルールは、複数の範囲変数を使用してカスタム コード メトリックを定義します:

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 }

多数の使用に注意 させる メイン クエリ ループ内の句は、クエリ実行のパフォーマンスを大幅に低下させる可能性があります。

letでクエリを開始

PRQL コンパイラは LINQ の使用を拡張します させる キーワード。PRQLでは、 させる キーワードを使用して、PRQL クエリの先頭で変数を定義できます。

たとえば、以下のデフォルト PRQL ルールは、まず次をマッチさせようとします BaseClass 型。見つかった場合は、次にクエリを実行します。

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

他の PRQL ルールでは、複数の次を通じて複数のサブセットを定義すると便利な場合があります させる クエリ自体を実行する前に、キーワード式を処理します。

たとえば、以下のデフォルト PRQL ルールは、まずサブセットを定義します uiTypesdbTypes クエリコードで使用する前に。

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 }

クエリでプロシージャを定義

LINQ 構文を使用すると、クエリ内でプロシージャを作成できます。これは、クエリ内のさまざまな場所からそのようなプロシージャを呼び出したい場合に便利です。

この可能性は、次のデフォルト ルールで示されています。そこでは、型が次かどうかをチェックする手順が デッド型と見なせる doit être invoqué depuis deux emplacements différents :

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

今すぐCppDependを試す

ドキュメントの全機能にアクセスできる14日間無料トライアル。クレジットカード不要。