You can build a unit dependency tree, wich shows the direct dependency for each unit in your project using the New Rtti.
Here a short description of the algorithm used in this code.
- For each Type(TRttiType) in the list do the following
- check if the basetype exist in the same unit else add the unit to the list.
- for each public field in the current type check if exist in the same unit else add the unit to the list.
- for each method in the current type with an valid ReturnType check if exist in the same unit else add the unit to the list.
- for each property in the current type check if exist in the same unit else add the unit to the list.
Limitations:
- Only show direct dependency of the units (example if Unit A depends on Unit B and Unit B depends on UnitC, the tree will show wich the Unit A depends on only of Unit B)
- Only supports Types with Rtti info.
- Due to Rtti Limitations only supports public fields (
TRttiField
).
uses Rtti, Generics.Collections, TypInfo; procedure FillTreeUnits(TreeViewUnits:TTreeView); var ctx : TRttiContext; TypeList : TArray<TRttiType>; lType : TRttiType; lMethod : TRttiMethod; lProperty: TRttiProperty; lField : TRttiField; Node : TTreeNode; UnitName : string; RefUnit : string; UnitsDict: TObjectDictionary<String, TStringList>; UnitList : TStringList; function GetUnitName(lType: TRttiType): string; begin { if lType.IsInstance then Result:=lType.UnitName else } Result := StringReplace(lType.QualifiedName, '.' + lType.Name, '',[rfReplaceAll]); end; //Check if exist the Unit in the Dictionary and if has a Unit Children in the associated list procedure CheckAndAdd(UnitName,RefUnit:string); begin if UnitName<>RefUnit then if not UnitsDict.ContainsKey(UnitName) then begin UnitList:=TStringList.Create; UnitList.Add(RefUnit); UnitsDict.Add(UnitName,UnitList); end else begin UnitList:=UnitsDict.Items[UnitName]; if UnitList.IndexOf(RefUnit)<0 then UnitList.Add(RefUnit); end; end; begin ctx := TRttiContext.Create; UnitsDict := TObjectDictionary<String, TStringList>.Create([doOwnsValues]); TreeViewUnits.Items.BeginUpdate; try TreeViewUnits.Items.Clear; TypeList:= ctx.GetTypes; //Fill a Dictionary with all the units and the dependencies for lType in TypeList do begin //Search references to another units in the BaseType UnitName:=GetUnitName(lType); if Assigned(lType.BaseType) then CheckAndAdd(UnitName,GetUnitName(lType.BaseType)); //Search references to another units in the public fields (due to RTTI limitations only works with public fields) for lField in lType.GetDeclaredFields do if Assigned(lField.FieldType) and (lField.FieldType.IsPublicType) then CheckAndAdd(UnitName,GetUnitName(lField.FieldType)); //Search references to another units in the properties for lProperty in lType.GetDeclaredProperties do if Assigned(lProperty.PropertyType) then CheckAndAdd(UnitName,GetUnitName(lProperty.PropertyType)); //Search references to another units in functions with ExtendedInfo (HasExtendedInfo=True) for lMethod in lType.GetDeclaredMethods do if (lMethod.HasExtendedInfo) and (lMethod.MethodKind in [mkFunction,mkClassFunction]) then CheckAndAdd(UnitName,GetUnitName(lMethod.ReturnType)); end; //finally fill the treeview for UnitName in UnitsDict.Keys do begin UnitList:=UnitsDict.Items[UnitName]; Node :=TreeViewUnits.Items.Add(nil,UnitName); for RefUnit in UnitList do TreeViewUnits.Items.AddChild(Node,RefUnit); end; finally UnitsDict.Destroy; ctx.Free; TreeViewUnits.Items.EndUpdate; end; end;
Finally the output for the source code