mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-12 20:40:31 +01:00
codetools: FindDanglingComponentEvents: check sub persistents in properties, bug #16831
git-svn-id: trunk@26455 -
This commit is contained in:
parent
97ae6679ec
commit
14c0ca0b26
@ -672,7 +672,8 @@ type
|
|||||||
const AClassName: string;
|
const AClassName: string;
|
||||||
RootComponent: TComponent; ExceptionOnClassNotFound,
|
RootComponent: TComponent; ExceptionOnClassNotFound,
|
||||||
SearchInAncestors: boolean;
|
SearchInAncestors: boolean;
|
||||||
out ListOfPInstancePropInfo: TFPList): boolean;
|
out ListOfPInstancePropInfo: TFPList;
|
||||||
|
const OverrideGetMethodName: TOnGetMethodname = nil): boolean;
|
||||||
|
|
||||||
// functions for events in the object inspector
|
// functions for events in the object inspector
|
||||||
function GetCompatiblePublishedMethods(Code: TCodeBuffer;
|
function GetCompatiblePublishedMethods(Code: TCodeBuffer;
|
||||||
@ -4691,9 +4692,9 @@ end;
|
|||||||
|
|
||||||
function TCodeToolManager.FindDanglingComponentEvents(Code: TCodeBuffer;
|
function TCodeToolManager.FindDanglingComponentEvents(Code: TCodeBuffer;
|
||||||
const AClassName: string; RootComponent: TComponent;
|
const AClassName: string; RootComponent: TComponent;
|
||||||
ExceptionOnClassNotFound, SearchInAncestors: boolean;
|
ExceptionOnClassNotFound, SearchInAncestors: boolean; out
|
||||||
out ListOfPInstancePropInfo: TFPList
|
ListOfPInstancePropInfo: TFPList;
|
||||||
): boolean;
|
const OverrideGetMethodName: TOnGetMethodname): boolean;
|
||||||
begin
|
begin
|
||||||
Result:=false;
|
Result:=false;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
@ -4704,7 +4705,7 @@ begin
|
|||||||
try
|
try
|
||||||
Result:=FCurCodeTool.FindDanglingComponentEvents(AClassName,RootComponent,
|
Result:=FCurCodeTool.FindDanglingComponentEvents(AClassName,RootComponent,
|
||||||
ExceptionOnClassNotFound,SearchInAncestors,
|
ExceptionOnClassNotFound,SearchInAncestors,
|
||||||
ListOfPInstancePropInfo);
|
ListOfPInstancePropInfo,OverrideGetMethodName);
|
||||||
except
|
except
|
||||||
on e: Exception do Result:=HandleException(e);
|
on e: Exception do Result:=HandleException(e);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -157,6 +157,24 @@ type
|
|||||||
procedure ReplaceString(var s: string);
|
procedure ReplaceString(var s: string);
|
||||||
function CalcMemSize: PtrUInt;
|
function CalcMemSize: PtrUInt;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCTComponentAccess = class(TComponent);
|
||||||
|
|
||||||
|
{ TComponentChildCollector }
|
||||||
|
|
||||||
|
TComponentChildCollector = class
|
||||||
|
private
|
||||||
|
FChilds: TFPList;
|
||||||
|
FRoot: TComponent;
|
||||||
|
procedure AddChildComponent(Child: TComponent);
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
function GetComponents(RootComponent: TComponent; AddRoot: boolean = true): TFPList;
|
||||||
|
property Childs: TFPList read FChilds;
|
||||||
|
property Root: TComponent read FRoot;
|
||||||
|
end;
|
||||||
|
|
||||||
function CompareStringToStringItems(Data1, Data2: Pointer): integer;
|
function CompareStringToStringItems(Data1, Data2: Pointer): integer;
|
||||||
function CompareStringAndStringToStringTreeItem(Key, Data: Pointer): integer;
|
function CompareStringAndStringToStringTreeItem(Key, Data: Pointer): integer;
|
||||||
@ -674,5 +692,45 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TComponentChildCollector }
|
||||||
|
|
||||||
|
procedure TComponentChildCollector.AddChildComponent(Child: TComponent);
|
||||||
|
var
|
||||||
|
OldRoot: TComponent;
|
||||||
|
begin
|
||||||
|
//debugln(['TComponentChildCollector.AddChildComponent ',DbgSName(Child)]);
|
||||||
|
Childs.Add(Child);
|
||||||
|
OldRoot := Root;
|
||||||
|
try
|
||||||
|
if csInline in Child.ComponentState then
|
||||||
|
FRoot := Child;
|
||||||
|
TCTComponentAccess(Child).GetChildren(@AddChildComponent,Root);
|
||||||
|
finally
|
||||||
|
FRoot := OldRoot;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TComponentChildCollector.Create;
|
||||||
|
begin
|
||||||
|
FChilds:=TFPList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TComponentChildCollector.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FChilds);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TComponentChildCollector.GetComponents(RootComponent: TComponent;
|
||||||
|
AddRoot: boolean): TFPList;
|
||||||
|
begin
|
||||||
|
Childs.Clear;
|
||||||
|
if AddRoot then
|
||||||
|
Childs.Add(RootComponent);
|
||||||
|
FRoot:=RootComponent;
|
||||||
|
TCTComponentAccess(RootComponent).GetChildren(@AddChildComponent,FRoot);
|
||||||
|
Result:=Childs;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|||||||
@ -4274,6 +4274,7 @@ begin
|
|||||||
AVLNode:=PosTree.FindHighest;
|
AVLNode:=PosTree.FindHighest;
|
||||||
while AVLNode<>nil do begin
|
while AVLNode<>nil do begin
|
||||||
StartPos:=PChar(AVLNode.Data)-PChar(Pointer(Src))+1;
|
StartPos:=PChar(AVLNode.Data)-PChar(Pointer(Src))+1;
|
||||||
|
// ToDo: if an include file is included twice a code position could be duplicated
|
||||||
if CleanPosToCaret(StartPos,ReferencePos) then
|
if CleanPosToCaret(StartPos,ReferencePos) then
|
||||||
AddCodePosition(ListOfPCodeXYPosition,ReferencePos);
|
AddCodePosition(ListOfPCodeXYPosition,ReferencePos);
|
||||||
AVLNode:=PosTree.FindPrecessor(AVLNode);
|
AVLNode:=PosTree.FindPrecessor(AVLNode);
|
||||||
|
|||||||
@ -192,7 +192,8 @@ type
|
|||||||
function FindDanglingComponentEvents(const TheClassName: string;
|
function FindDanglingComponentEvents(const TheClassName: string;
|
||||||
RootComponent: TComponent; ExceptionOnClassNotFound,
|
RootComponent: TComponent; ExceptionOnClassNotFound,
|
||||||
SearchInAncestors: boolean;
|
SearchInAncestors: boolean;
|
||||||
out ListOfPInstancePropInfo: TFPList): boolean;
|
out ListOfPInstancePropInfo: TFPList;
|
||||||
|
const OverrideGetMethodName: TOnGetMethodname = nil): boolean;
|
||||||
|
|
||||||
// variables, constants, types
|
// variables, constants, types
|
||||||
function RemoveIdentifierDefinition(const CursorPos: TCodeXYPosition;
|
function RemoveIdentifierDefinition(const CursorPos: TCodeXYPosition;
|
||||||
@ -4968,8 +4969,9 @@ end;
|
|||||||
|
|
||||||
function TStandardCodeTool.FindDanglingComponentEvents(
|
function TStandardCodeTool.FindDanglingComponentEvents(
|
||||||
const TheClassName: string; RootComponent: TComponent;
|
const TheClassName: string; RootComponent: TComponent;
|
||||||
ExceptionOnClassNotFound, SearchInAncestors: boolean;
|
ExceptionOnClassNotFound, SearchInAncestors: boolean; out
|
||||||
out ListOfPInstancePropInfo: TFPList): boolean;
|
ListOfPInstancePropInfo: TFPList;
|
||||||
|
const OverrideGetMethodName: TOnGetMethodname): boolean;
|
||||||
var
|
var
|
||||||
PublishedMethods: TAVLTree;
|
PublishedMethods: TAVLTree;
|
||||||
|
|
||||||
@ -4987,7 +4989,7 @@ var
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure CheckMethodsInComponent(AComponent: TComponent);
|
procedure CheckMethodsInPersistent(APersistent: TPersistent);
|
||||||
var
|
var
|
||||||
TypeInfo: PTypeInfo;
|
TypeInfo: PTypeInfo;
|
||||||
TypeData: PTypeData;
|
TypeData: PTypeData;
|
||||||
@ -4997,13 +4999,14 @@ var
|
|||||||
NodeExt: TCodeTreeNodeExtension;
|
NodeExt: TCodeTreeNodeExtension;
|
||||||
CurMethod: TMethod;
|
CurMethod: TMethod;
|
||||||
CurMethodName: String;
|
CurMethodName: String;
|
||||||
|
ObjValue: TObject;
|
||||||
begin
|
begin
|
||||||
if AComponent=nil then exit;
|
if APersistent=nil then exit;
|
||||||
{$IFDEF VerboseDanglingComponentEvents}
|
{$IFDEF VerboseDanglingComponentEvents}
|
||||||
debugln('TStandardCodeTool.FindDanglingComponentEvents Checking ',DbgSName(AComponent));
|
debugln('TStandardCodeTool.FindDanglingComponentEvents.CheckMethodsInPersistent Checking ',DbgSName(APersistent));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
// read all properties and remove doubles
|
// read all properties and remove doubles
|
||||||
TypeInfo:=AComponent.ClassInfo;
|
TypeInfo:=APersistent.ClassInfo;
|
||||||
repeat
|
repeat
|
||||||
// read all property infos of current class
|
// read all property infos of current class
|
||||||
TypeData:=GetTypeData(TypeInfo);
|
TypeData:=GetTypeData(TypeInfo);
|
||||||
@ -5023,22 +5026,41 @@ var
|
|||||||
debugln(' Property ',PropInfo^.Name,' Type=',PropInfo^.PropType^.Name);
|
debugln(' Property ',PropInfo^.Name,' Type=',PropInfo^.PropType^.Name);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
PropType:=PropInfo^.PropType;
|
PropType:=PropInfo^.PropType;
|
||||||
if PropType^.Kind=tkMethod then begin
|
|
||||||
|
if (PropType^.Kind=tkMethod) then begin
|
||||||
// RTTI property is method
|
// RTTI property is method
|
||||||
// -> search method in source
|
// -> search method in source
|
||||||
CurMethod:=GetMethodProp(AComponent,PropInfo);
|
CurMethod:=GetMethodProp(APersistent,PropInfo);
|
||||||
CurMethodName:=OnGetMethodName(CurMethod,RootComponent);
|
if (CurMethod.Data<>nil) or (CurMethod.Code<>nil) then begin
|
||||||
{$IFDEF VerboseDanglingComponentEvents}
|
if Assigned(OverrideGetMethodName) then
|
||||||
if (CurMethod.Data<>nil) or (CurMethod.COde<>nil) then
|
CurMethodName:=OverrideGetMethodName(CurMethod,RootComponent)
|
||||||
debugln(' Component ',DbgSName(AComponent),' Property ',PropInfo^.Name,' Type=',PropInfo^.PropType^.Name,' CurMethodName="',CurMethodName,'"');
|
else
|
||||||
{$ENDIF}
|
CurMethodName:=OnGetMethodName(CurMethod,RootComponent);
|
||||||
if CurMethodName<>'' then begin
|
{$IFDEF VerboseDanglingComponentEvents}
|
||||||
NodeExt:=FindCodeTreeNodeExt(PublishedMethods,CurMethodName);
|
debugln(' Persistent ',DbgSName(APersistent),' Property ',PropInfo^.Name,' Type=',PropInfo^.PropType^.Name,' CurMethodName="',CurMethodName,'"');
|
||||||
if NodeExt=nil then begin
|
{$ENDIF}
|
||||||
// method not found -> dangling event
|
if CurMethodName<>'' then begin
|
||||||
AddDanglingEvent(AComponent,PropInfo);
|
NodeExt:=FindCodeTreeNodeExt(PublishedMethods,CurMethodName);
|
||||||
|
if NodeExt=nil then begin
|
||||||
|
// method not found -> dangling event
|
||||||
|
AddDanglingEvent(APersistent,PropInfo);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end else if (PropType^.Kind=tkClass) then begin
|
||||||
|
// RTTI property is class instance
|
||||||
|
ObjValue := TObject(GetObjectProp(APersistent, PropInfo));
|
||||||
|
if ObjValue is TCollection then begin
|
||||||
|
// collection
|
||||||
|
|
||||||
|
end else if (ObjValue is TPersistent)
|
||||||
|
and (not (ObjValue is TComponent)
|
||||||
|
or (csSubComponent in TComponent(ObjValue).ComponentStyle))
|
||||||
|
then begin
|
||||||
|
// sub persistent (e.g. Canvas.Font)
|
||||||
|
//debugln(['CheckMethodsInPersistent sub persistent: ',DbgSName(ObjValue)]);
|
||||||
|
CheckMethodsInPersistent(TPersistent(ObjValue));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
PropInfo:=PPropInfo(pointer(@PropInfo^.Name)+PByte(@PropInfo^.Name)^+1);
|
PropInfo:=PPropInfo(pointer(@PropInfo^.Name)+PByte(@PropInfo^.Name)^+1);
|
||||||
dec(CurCount);
|
dec(CurCount);
|
||||||
@ -5049,9 +5071,13 @@ var
|
|||||||
|
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
Collector: TComponentChildCollector;
|
||||||
|
AllComponents: TFPList;
|
||||||
begin
|
begin
|
||||||
PublishedMethods:=nil;
|
PublishedMethods:=nil;
|
||||||
ListOfPInstancePropInfo:=nil;
|
ListOfPInstancePropInfo:=nil;
|
||||||
|
Collector:=nil;
|
||||||
|
AllComponents:=nil;
|
||||||
try
|
try
|
||||||
// search all available published methods
|
// search all available published methods
|
||||||
{$IFDEF VerboseDanglingComponentEvents}
|
{$IFDEF VerboseDanglingComponentEvents}
|
||||||
@ -5062,10 +5088,12 @@ begin
|
|||||||
PublishedMethods);
|
PublishedMethods);
|
||||||
if not Result then exit;
|
if not Result then exit;
|
||||||
// go through all components
|
// go through all components
|
||||||
CheckMethodsInComponent(RootComponent);
|
Collector:=TComponentChildCollector.Create;
|
||||||
for i:=0 to RootComponent.ComponentCount-1 do
|
AllComponents:=Collector.GetComponents(RootComponent,true);
|
||||||
CheckMethodsInComponent(RootComponent.Components[i]);
|
for i:=0 to AllComponents.Count-1 do
|
||||||
|
CheckMethodsInPersistent(TComponent(AllComponents[i]));
|
||||||
finally
|
finally
|
||||||
|
Collector.Free;
|
||||||
NodeExtMemManager.DisposeAVLTree(PublishedMethods);
|
NodeExtMemManager.DisposeAVLTree(PublishedMethods);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -301,7 +301,8 @@ begin
|
|||||||
// find all dangling events
|
// find all dangling events
|
||||||
//debugln('RemoveDanglingEvents A ',PascalBuffer.Filename,' ',DbgSName(RootComponent));
|
//debugln('RemoveDanglingEvents A ',PascalBuffer.Filename,' ',DbgSName(RootComponent));
|
||||||
if not CodeToolBoss.FindDanglingComponentEvents(PascalBuffer,
|
if not CodeToolBoss.FindDanglingComponentEvents(PascalBuffer,
|
||||||
RootComponent.ClassName,RootComponent,false,true,ListOfPInstancePropInfo)
|
RootComponent.ClassName,RootComponent,false,true,ListOfPInstancePropInfo,
|
||||||
|
@BaseFormEditor1.OnGetDanglingMethodName)
|
||||||
then begin
|
then begin
|
||||||
//debugln('RemoveDanglingEvents Errors in code');
|
//debugln('RemoveDanglingEvents Errors in code');
|
||||||
if OkOnCodeErrors then
|
if OkOnCodeErrors then
|
||||||
|
|||||||
@ -155,6 +155,8 @@ type
|
|||||||
var Handled: boolean);
|
var Handled: boolean);
|
||||||
function SaveUnitComponentToBinStream(AnUnitInfo: TUnitInfo;
|
function SaveUnitComponentToBinStream(AnUnitInfo: TUnitInfo;
|
||||||
var BinCompStream: TExtMemoryStream): TModalResult;
|
var BinCompStream: TExtMemoryStream): TModalResult;
|
||||||
|
function OnGetDanglingMethodName(const AMethod: TMethod;
|
||||||
|
aRootComponent: TObject): string;
|
||||||
|
|
||||||
// ancestors
|
// ancestors
|
||||||
function GetAncestorLookupRoot(AComponent: TComponent): TComponent; override;
|
function GetAncestorLookupRoot(AComponent: TComponent): TComponent; override;
|
||||||
@ -973,6 +975,20 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCustomFormEditor.OnGetDanglingMethodName(const AMethod: TMethod;
|
||||||
|
aRootComponent: TObject): string;
|
||||||
|
// check if event is a JITMethod of aRootComponent
|
||||||
|
var
|
||||||
|
JITMethod: TJITMethod;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
if IsJITMethod(aMethod) then begin
|
||||||
|
JITMethod:=TJITMethod(aMethod.Data);
|
||||||
|
if aRootComponent.ClassType=JITMethod.TheClass then
|
||||||
|
Result:=JITMethod.TheMethodName;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCustomFormEditor.DesignerCount: integer;
|
function TCustomFormEditor.DesignerCount: integer;
|
||||||
begin
|
begin
|
||||||
Result:=JITFormList.Count+JITNonFormList.Count;
|
Result:=JITFormList.Count+JITNonFormList.Count;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user