codetools: find gdb line: search implementation, started searching members

git-svn-id: trunk@44935 -
This commit is contained in:
mattias 2014-05-06 15:43:42 +00:00
parent dd68e3e52e
commit 334403f906
3 changed files with 194 additions and 47 deletions

View File

@ -761,7 +761,11 @@ type
out NewPos: TCodeXYPosition; out NewTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer;
IgnoreTypeLess: boolean = false): boolean; IgnoreTypeLess: boolean = false): boolean;
function FindDeclarationNodeInInterface(const Identifier: string; function FindDeclarationNodeInInterface(const Identifier: string;
BuildTheTree: Boolean): TCodeTreeNode;// search for type, const, var BuildTheTree: Boolean): TCodeTreeNode;// search for type, const, var, proc, prop
function FindDeclarationNodeInImplementation(Identifier: string;
BuildTheTree: Boolean): TCodeTreeNode;// search for type, const, var, proc, prop
function FindSubDeclaration(Identifier: string; ParentNode: TCodeTreeNode
): TCodeTreeNode; // search for type, const, var, proc, prop
function FindInitializationSection: TCodeTreeNode; deprecated; // use FindInitializationNode function FindInitializationSection: TCodeTreeNode; deprecated; // use FindInitializationNode
function FindMainUsesSection(UseContainsSection: boolean = false): TCodeTreeNode; function FindMainUsesSection(UseContainsSection: boolean = false): TCodeTreeNode;
@ -1911,6 +1915,43 @@ begin
Result:=CacheEntry^.Node; Result:=CacheEntry^.Node;
end; end;
function TFindDeclarationTool.FindDeclarationNodeInImplementation(
Identifier: string; BuildTheTree: Boolean): TCodeTreeNode;
begin
Result:=nil;
if Identifier='' then exit;
if BuildTheTree then
BuildTree(lsrInitializationStart);
Result:=FindSubDeclaration(Identifier,FindImplementationNode);
end;
function TFindDeclarationTool.FindSubDeclaration(Identifier: string;
ParentNode: TCodeTreeNode): TCodeTreeNode;
var
LastNode: TCodeTreeNode;
begin
Result:=nil;
if ParentNode=nil then exit;
if Identifier='' then exit;
Identifier:=UpperCaseStr(Identifier);
LastNode:=ParentNode.NextSkipChilds;
Result:=ParentNode.Next;
while Result<>LastNode do begin
// ToDo: check enums
if Result.Desc in AllIdentifierDefinitions then begin
if CompareNodeIdentChars(Result,Identifier)=0 then
exit;
Result:=Result.NextSkipChilds;
end else if Result.Desc=ctnProcedure then begin
if CompareIdentifiers(PChar(ExtractProcName(Result,[])),PChar(Pointer(Identifier)))=0 then
exit;
Result:=Result.NextSkipChilds;
end else
Result:=Result.Next;
end;
Result:=nil;
end;
function TFindDeclarationTool.FindMainUsesSection(UseContainsSection: boolean function TFindDeclarationTool.FindMainUsesSection(UseContainsSection: boolean
): TCodeTreeNode; ): TCodeTreeNode;
begin begin

View File

@ -31,9 +31,10 @@ unit CodyFindGDBLine;
interface interface
uses uses
Classes, SysUtils, FileUtil, LazLoggerBase, LazLogger, SynEdit, Classes, SysUtils, FileUtil, LazLoggerBase, LazLogger, SynEdit, IDEDialogs,
IDEDialogs, SrcEditorIntf, Forms, Controls, Graphics, Dialogs, StdCtrls, SrcEditorIntf, LazIDEIntf, ProjectIntf, Forms, Controls, Graphics, Dialogs,
ExtCtrls, ButtonPanel, CodyStrConsts, CodeCache, CodeToolManager, CodeTree; StdCtrls, ExtCtrls, ButtonPanel, CodyStrConsts, CodeCache, CodeToolManager,
CodeTree, KeywordFuncLists;
type type
@ -69,7 +70,8 @@ type
procedure Jump; procedure Jump;
procedure ParseGDBBacktraceLine(Line: string; out Identifier, TheErrorMsg: string); procedure ParseGDBBacktraceLine(Line: string; out Identifier, TheErrorMsg: string);
procedure FindGDBIdentifier(GDBIdentifier: string; out TheErrorMsg: string); procedure FindGDBIdentifier(GDBIdentifier: string; out TheErrorMsg: string);
procedure FindUnit(TheUnitName: string; out aFilename: string); function FindUnit(TheUnitName: string; out aFilename: string): boolean;
function FindProgram(TheSrcName: string; out aFilename: string): boolean;
public public
property IdleConnected: boolean read FIdleConnected write SetIdleConnected; property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
property ErrorMsg: string read FErrorMsg; property ErrorMsg: string read FErrorMsg;
@ -339,26 +341,37 @@ end;
procedure TCodyFindGDBLineDialog.FindGDBIdentifier(GDBIdentifier: string; out procedure TCodyFindGDBLineDialog.FindGDBIdentifier(GDBIdentifier: string; out
TheErrorMsg: string); TheErrorMsg: string);
{ Examples: { Examples:
fpc_raiseexception compiler built-in
SYSUTILS_RUNERRORTOEXCEPT$LONGINT$POINTER$POINTER fpc_raiseexception
SYSTEM_HANDLEERRORADDRFRAME$LONGINT$POINTER$POINTER ??
?? PASCALMAIN
EXTTOOLEDITDLG_TEXTERNALTOOLMENUITEMS_$__LOAD$TCONFIGSTORAGE$$TMODALRESULT SYSTEM_FPC_SYSTEMMAIN$LONGINT$PPCHAR$PPCHAR
EXTTOOLEDITDLG_TEXTERNALTOOLMENUITEMS_$__LOAD$TCONFIGSTORAGE$ANSISTRING$$TMODALRESULT
ENVIRONMENTOPTS_TENVIRONMENTOPTIONS_$__LOAD$BOOLEAN unit:
MAIN_TMAINIDE_$__LOADGLOBALOPTIONS procedure
MAIN_TMAINIDE_$__CREATE$TCOMPONENT$$TMAINIDE SYSUTILS_RUNERRORTOEXCEPT$LONGINT$POINTER$POINTER
PASCALMAIN SYSTEM_HANDLEERRORADDRFRAME$LONGINT$POINTER$POINTER
SYSTEM_FPC_SYSTEMMAIN$LONGINT$PPCHAR$PPCHAR method
EXTTOOLEDITDLG_TEXTERNALTOOLMENUITEMS_$__LOAD$TCONFIGSTORAGE$$TMODALRESULT
EXTTOOLEDITDLG_TEXTERNALTOOLMENUITEMS_$__LOAD$TCONFIGSTORAGE$ANSISTRING$$TMODALRESULT
ENVIRONMENTOPTS_TENVIRONMENTOPTIONS_$__LOAD$BOOLEAN
MAIN_TMAINIDE_$__LOADGLOBALOPTIONS
MAIN_TMAINIDE_$__CREATE$TCOMPONENT$$TMAINIDE
program:
P$TESTSTACKTRACE1_TMAINCLASS_$_TSUBCLASS_$__RAISESOMETHING$ANSISTRING
} }
var var
p: PChar; p: PChar;
TheUnitName: string; TheSrcName: string;
Code: TCodeBuffer; Code: TCodeBuffer;
CurIdentifier: string; CurIdentifier: string;
Tool: TCodeTool; Tool: TCodeTool;
Node: TCodeTreeNode; Node: TCodeTreeNode;
CodeXY: TCodeXYPosition; CodeXY: TCodeXYPosition;
SubNode: TCodeTreeNode;
ClassNode: TCodeTreeNode;
ProcNode: TCodeTreeNode;
procedure ReadIdentifier(out Identifier: string); procedure ReadIdentifier(out Identifier: string);
var var
@ -380,21 +393,34 @@ begin
TheErrorMsg:='compiler built in function "'+GDBIdentifier+'"'; TheErrorMsg:='compiler built in function "'+GDBIdentifier+'"';
exit; exit;
end; end;
TheSrcName:='';
if p^ in ['A'..'Z'] then begin if p^ in ['A'..'Z'] then begin
ReadIdentifier(TheUnitName); ReadIdentifier(TheSrcName);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier first identifier=',TheUnitName]); debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier first identifier=',TheSrcName,' ...']);
if p^<>'_' then begin if p^='$' then begin
// P$programname
inc(p);
if IsIdentStartChar[p^] then
ReadIdentifier(TheSrcName);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier search source of program "',TheSrcName,'" ...']);
FindProgram(TheSrcName,FSrcFilename);
if (SrcFilename='') then begin
TheErrorMsg:='can''t find program "'+TheSrcName+'"';
exit;
end;
end else if p^='_' then begin
// a unit name
// => search unit
FindUnit(TheSrcName,FSrcFilename);
if (SrcFilename='') then begin
TheErrorMsg:='can''t find unit '+TheSrcName;
exit;
end;
end else if p^<>'_' then begin
// only one uppercase identifier, e.g. PASCALMAIN // only one uppercase identifier, e.g. PASCALMAIN
TheErrorMsg:='compiler built in function "'+GDBIdentifier+'"'; TheErrorMsg:='compiler built in function "'+GDBIdentifier+'"';
exit; exit;
end; end;
// a unit name
// => search
FindUnit(TheUnitName,FSrcFilename);
if (SrcFilename='') then begin
TheErrorMsg:='can''t find unit '+TheUnitName;
exit;
end;
// load unit source // load unit source
Code:=CodeToolBoss.LoadFile(SrcFilename,true,false); Code:=CodeToolBoss.LoadFile(SrcFilename,true,false);
if Code=nil then begin if Code=nil then begin
@ -406,36 +432,85 @@ begin
if p^ in ['A'..'Z'] then begin if p^ in ['A'..'Z'] then begin
ReadIdentifier(CurIdentifier); ReadIdentifier(CurIdentifier);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier Identifier="',CurIdentifier,'"']); debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier Identifier="',CurIdentifier,'"']);
if not CodeToolBoss.Explore(Code,Tool,false,true) then begin if not CodeToolBoss.Explore(Code,Tool,false,true) then begin
// syntax error in source => use only SrcFilename debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier parse error']);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier identifier "',CurIdentifier,'" not found in "',Code.Filename,'" due to syntax error']); TheErrorMsg:=CodeToolBoss.ErrorMessage;
exit; exit;
end; end;
Node:=Tool.FindDeclarationNodeInInterface(CurIdentifier,true); Node:=nil;
// search in interface
try
Node:=Tool.FindDeclarationNodeInInterface(CurIdentifier,true);
except
on E: Exception do begin
CodeToolBoss.HandleException(E);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier parse error in "',Code.Filename,'": ',E.Message]);
TheErrorMsg:=CodeToolBoss.ErrorMessage;
exit;
end;
end;
if Node=nil then begin
// search in implementation
try
Node:=Tool.FindDeclarationNodeInImplementation(CurIdentifier,true);
except
on E: Exception do begin
CodeToolBoss.HandleException(E);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier parse error in "',Code.Filename,'": ',E.Message]);
TheErrorMsg:=CodeToolBoss.ErrorMessage;
exit;
end;
end;
end;
if Node=nil then begin if Node=nil then begin
// identifier not found => use only SrcFilename // identifier not found => use only SrcFilename
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier identifier "',CurIdentifier,'" not found in "',Code.Filename,'"']); debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier identifier "',CurIdentifier,'" not found in "',Code.Filename,'"']);
TheErrorMsg:='identifier "'+CurIdentifier+'" not found in "'+Code.Filename+'"';
exit; exit;
end; end;
// identifier found
while (p^='_') and (p[1]='$') and (p[2]='_') and (p[3]='_') do begin
inc(p,4);
if p^ in ['A'..'Z'] then begin
// _$__identifier => sub identifier
ReadIdentifier(CurIdentifier);
// find sub identifier
SubNode:=Tool.FindSubDeclaration(CurIdentifier,Node);
if SubNode=nil then begin
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier SubIdentifier="',CurIdentifier,'" not found']);
break;
end else begin
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier SubIdentifier="',CurIdentifier,'" found']);
Node:=SubNode;
end;
end else begin
break;
end;
end;
if Node.Desc=ctnProcedure then begin
// proc node => find body
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier AAA1']);
ClassNode:=Tool.FindClassOrInterfaceNode(Node);
if ClassNode<>nil then begin
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier AAA2']);
ProcNode:=Tool.FindCorrespondingProcNode(Node);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier AAA3 ',ProcNode<>nil]);
if ProcNode<>nil then
Node:=ProcNode;
end;
end;
// (part of) identifier found
Tool.CleanPosToCaret(Node.StartPos,CodeXY); Tool.CleanPosToCaret(Node.StartPos,CodeXY);
fSrcFilename:=CodeXY.Code.Filename; fSrcFilename:=CodeXY.Code.Filename;
FSrcXY.Y:=CodeXY.Y; FSrcXY.Y:=CodeXY.Y;
FSrcXY.X:=CodeXY.X; FSrcXY.X:=CodeXY.X;
if (p^='_') and (p[1]='$') and (p[2]='_') and (p[3]='_') then begin
inc(p,4);
if p^ in ['A'..'Z'] then begin
ReadIdentifier(CurIdentifier);
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier SubIdentifier="',CurIdentifier,'"']);
// find sub identifier
end;
end;
end; end;
// unknown operator => use only SrcFilename // unknown operator => use only SrcFilename
debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier unknown operator ',dbgstr(p^)]); debugln(['TCodyFindGDBLineDialog.FindGDBIdentifier operator not yet supported: ',dbgstr(p^)]);
exit; exit;
end else begin end else begin
// example: ?? // example: ??
@ -444,8 +519,8 @@ begin
TheErrorMsg:='unkown identifier "'+GDBIdentifier+'"'; TheErrorMsg:='unkown identifier "'+GDBIdentifier+'"';
end; end;
procedure TCodyFindGDBLineDialog.FindUnit(TheUnitName: string; out function TCodyFindGDBLineDialog.FindUnit(TheUnitName: string; out
aFilename: string); aFilename: string): boolean;
var var
i: Integer; i: Integer;
SrcEdit: TSourceEditorInterface; SrcEdit: TSourceEditorInterface;
@ -456,7 +531,7 @@ begin
aFilename:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath( aFilename:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
'',TheUnitName,InFilename,true); '',TheUnitName,InFilename,true);
if aFilename<>'' then if aFilename<>'' then
exit; exit(true);
// search in source editor // search in source editor
for i:=0 to SourceEditorManagerIntf.SourceEditorCount-1 do begin for i:=0 to SourceEditorManagerIntf.SourceEditorCount-1 do begin
SrcEdit:=SourceEditorManagerIntf.SourceEditors[i]; SrcEdit:=SourceEditorManagerIntf.SourceEditors[i];
@ -464,10 +539,41 @@ begin
if not FilenameIsPascalUnit(aFileName) then continue; if not FilenameIsPascalUnit(aFileName) then continue;
if CompareText(ExtractFileNameOnly(aFileName),TheUnitName)<>0 then if CompareText(ExtractFileNameOnly(aFileName),TheUnitName)<>0 then
continue; continue;
exit; exit(true);
end; end;
// not found // not found
aFilename:=''; aFilename:='';
Result:=false;
end;
function TCodyFindGDBLineDialog.FindProgram(TheSrcName: string; out
aFilename: string): boolean;
var
aProject: TLazProject;
i: Integer;
SrcEdit: TSourceEditorInterface;
begin
// check active project
aProject:=LazarusIDE.ActiveProject;
if (aProject<>nil) and (aProject.MainFile<>nil) then begin
aFilename:=aProject.MainFile.Filename;
if FilenameIsAbsolute(aFilename)
and ((TheSrcName='')
or (SysUtils.CompareText(ExtractFileNameOnly(aFilename),TheSrcName)=0))
then
exit(true);
end;
// search in source editor
for i:=0 to SourceEditorManagerIntf.SourceEditorCount-1 do begin
SrcEdit:=SourceEditorManagerIntf.SourceEditors[i];
aFilename:=SrcEdit.FileName;
if CompareText(ExtractFileNameOnly(aFileName),TheSrcName)<>0 then
continue;
exit(true);
end;
// not found
aFilename:='';
Result:=false;
end; end;
procedure TCodyFindGDBLineDialog.FormClose(Sender: TObject; procedure TCodyFindGDBLineDialog.FormClose(Sender: TObject;

View File

@ -112,7 +112,7 @@ begin
raise Exception.Create('cody: command category '+CommandCategoryViewName+' not found'); raise Exception.Create('cody: command category '+CommandCategoryViewName+' not found');
// Search menu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Search menu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FindGDBLineCommand:=RegisterIDECommand(CmdCatSearchReplace, 'ShowPPUList', FindGDBLineCommand:=RegisterIDECommand(CmdCatSearchReplace, 'FindGDBBacktrace',
crsFindGDBBacktraceLine, crsFindGDBBacktraceLine,
CleanIDEShortCut,CleanIDEShortCut,nil,@ShowFindGDBLineDialog); CleanIDEShortCut,CleanIDEShortCut,nil,@ShowFindGDBLineDialog);
RegisterIDEMenuCommand(itmCodeToolSearches,'FindGDBBacktraceLine',crsFindGDBBacktraceLine, RegisterIDEMenuCommand(itmCodeToolSearches,'FindGDBBacktraceLine',crsFindGDBBacktraceLine,