mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-11 13:28:04 +02:00
codetools: implemented AddMethods
git-svn-id: trunk@13204 -
This commit is contained in:
parent
7cac0aa984
commit
6060a047ed
@ -274,11 +274,15 @@ function RemoveFormComponentFromSource(Source:TSourceLog;
|
||||
function FindClassAncestorName(const Source, FormClassName: string): string;
|
||||
|
||||
// procedure specifiers
|
||||
function FindFirstProcSpecifier(const ProcText: string;
|
||||
NestedComments: boolean = false; CaseSensitive: boolean = false): integer;
|
||||
function SearchProcSpecifier(const ProcText, Specifier: string;
|
||||
out SpecifierEndPosition: integer;
|
||||
NestedComments: boolean = false;
|
||||
WithSpaceBehindSemicolon: boolean = true;
|
||||
CaseSensitive: boolean = false): integer;
|
||||
function RemoveProcSpecifier(const ProcText, Specifier: string;
|
||||
NestedComments: boolean = false): string;
|
||||
|
||||
// code search
|
||||
function SearchCodeInSource(const Source, Find: string; StartPos: integer;
|
||||
@ -1467,6 +1471,31 @@ begin
|
||||
while (IsIdentChar[Identifier[Result]]) do inc(Result);
|
||||
end;
|
||||
|
||||
function FindFirstProcSpecifier(const ProcText: string;
|
||||
NestedComments: boolean; CaseSensitive: boolean): integer;
|
||||
// length(ProcText)+1 on failure
|
||||
var
|
||||
AtomStart: integer;
|
||||
p: Integer;
|
||||
begin
|
||||
Result:=length(ProcText)+1;
|
||||
// read till first semicolon
|
||||
p:=1;
|
||||
while p<=length(ProcText) do begin
|
||||
ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments);
|
||||
if AtomStart>length(ProcText) then exit;
|
||||
if ProcText[AtomStart] in ['[','('] then begin
|
||||
if not ReadTilPascalBracketClose(ProcText,AtomStart,NestedComments) then
|
||||
exit;
|
||||
p:=AtomStart;
|
||||
end else if ProcText[AtomStart]=';' then begin
|
||||
ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments);
|
||||
Result:=p;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function SearchProcSpecifier(const ProcText, Specifier: string;
|
||||
out SpecifierEndPosition: integer; NestedComments: boolean;
|
||||
WithSpaceBehindSemicolon: boolean; CaseSensitive: boolean): integer;
|
||||
@ -1477,9 +1506,22 @@ function SearchProcSpecifier(const ProcText, Specifier: string;
|
||||
var
|
||||
AtomStart: integer;
|
||||
begin
|
||||
Result:=SearchCodeInSource(ProcText, Specifier, 1, SpecifierEndPosition,
|
||||
CaseSensitive, NestedComments);
|
||||
if Result<1 then exit;
|
||||
Result:=FindFirstProcSpecifier(ProcText,NestedComments);
|
||||
while Result<=length(ProcText) do begin
|
||||
ReadRawNextPascalAtom(ProcText,Result,AtomStart,NestedComments);
|
||||
if AtomStart>length(ProcText) then exit(-1);
|
||||
if CompareIdentifiers(@ProcText[AtomStart],@Specifier[1])=0 then begin
|
||||
Result:=AtomStart;
|
||||
break;
|
||||
end;
|
||||
if ProcText[AtomStart] in ['[','('] then begin
|
||||
if not ReadTilPascalBracketClose(ProcText,AtomStart,NestedComments)
|
||||
then
|
||||
exit(-1);
|
||||
Result:=AtomStart;
|
||||
end;
|
||||
end;
|
||||
SpecifierEndPosition:=Result;
|
||||
while (SpecifierEndPosition<=length(ProcText))
|
||||
and (ProcText[SpecifierEndPosition]<>';') do begin
|
||||
ReadRawNextPascalAtom(ProcText,SpecifierEndPosition,AtomStart,NestedComments);
|
||||
@ -1498,6 +1540,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function RemoveProcSpecifier(const ProcText, Specifier: string;
|
||||
NestedComments: boolean): string;
|
||||
var
|
||||
EndPos: integer;
|
||||
StartPos: LongInt;
|
||||
begin
|
||||
Result:=ProcText;
|
||||
StartPos:=SearchProcSpecifier(Result,Specifier,EndPos,NestedComments);
|
||||
if StartPos>=1 then
|
||||
Result:=copy(Result,1,StartPos-1)+copy(Result,EndPos,length(Result));
|
||||
end;
|
||||
|
||||
function ReadNextPascalAtom(const Source:string;
|
||||
var Position, AtomStart: integer; NestedComments: boolean):string;
|
||||
var DirectiveName:string;
|
||||
|
@ -5644,13 +5644,13 @@ var
|
||||
FullProcCode: String;
|
||||
VirtualStartPos: LongInt;
|
||||
VirtualEndPos: integer;
|
||||
AbstractStartPos: LongInt;
|
||||
AbstractEndPos: integer;
|
||||
VisibilityDesc: TCodeTreeNodeDesc;
|
||||
NodeExt: TCodeTreeNodeExtension;
|
||||
AVLNode: TAVLTreeNode;
|
||||
ProcName: String;
|
||||
NewClassPart: TNewClassPart;
|
||||
Beautifier: TBeautifyCodeOptions;
|
||||
ProcCode: String;
|
||||
begin
|
||||
Result:=false;
|
||||
if (ListOfPCodeXYPosition=nil) or (ListOfPCodeXYPosition.Count=0) then
|
||||
@ -5658,7 +5658,8 @@ begin
|
||||
|
||||
if (SourceChangeCache=nil) then
|
||||
RaiseException('need a SourceChangeCache');
|
||||
|
||||
|
||||
Beautifier:=SourceChangeCache.BeautifyCodeOptions;
|
||||
NewMethods:=TAVLTree.Create(@CompareCodeTreeNodeExt);
|
||||
try
|
||||
|
||||
@ -5694,7 +5695,7 @@ begin
|
||||
phpWithCallingSpecs,phpWithProcModifiers]);
|
||||
if VirtualToOverride then begin
|
||||
VirtualStartPos:=SearchProcSpecifier(FullProcCode,'virtual',
|
||||
VirtualEndPos,NewCodeTool.Scanner.NestedComments,false);
|
||||
VirtualEndPos,NewCodeTool.Scanner.NestedComments);
|
||||
if VirtualStartPos>=1 then begin
|
||||
// replace virtual with override
|
||||
FullProcCode:=copy(FullProcCode,1,VirtualStartPos-1)
|
||||
@ -5702,20 +5703,25 @@ begin
|
||||
+copy(FullProcCode,VirtualEndPos,length(FullProcCode));
|
||||
end;
|
||||
// remove abstract
|
||||
AbstractStartPos:=SearchProcSpecifier(FullProcCode,'abstract',
|
||||
AbstractEndPos,NewCodeTool.Scanner.NestedComments,true);
|
||||
if AbstractStartPos>=1 then begin
|
||||
// replace virtual with override
|
||||
FullProcCode:=copy(FullProcCode,1,AbstractStartPos-1)
|
||||
+copy(FullProcCode,AbstractEndPos,length(FullProcCode));
|
||||
end;
|
||||
FullProcCode:=RemoveProcSpecifier(FullProcCode,'abstract',
|
||||
NewCodeTool.Scanner.NestedComments);
|
||||
end;
|
||||
|
||||
ProcCode:=ExtractProcHead(ProcNode,[phpWithStart,
|
||||
phpAddClassname,phpWithVarModifiers,phpWithParameterNames,
|
||||
phpWithResultType,phpWithCallingSpecs]);
|
||||
ProcCode:=ProcCode+Beautifier.LineEnd
|
||||
+'begin'+Beautifier.LineEnd
|
||||
+GetIndentStr(Beautifier.Indent)+Beautifier.LineEnd
|
||||
+'end;';
|
||||
ProcCode:=Beautifier.BeautifyProc(ProcCode,0,false);
|
||||
|
||||
// add method data
|
||||
NodeExt:=NodeExtMemManager.NewNode;
|
||||
NodeExt.Txt:=CleanProcCode;
|
||||
NodeExt.ExtTxt1:=FullProcCode;
|
||||
NodeExt.ExtTxt2:=ProcName;
|
||||
NodeExt.ExtTxt3:=ProcCode;
|
||||
NodeExt.Flags:=VisibilityDesc;
|
||||
NewMethods.Add(NodeExt);
|
||||
DebugLn(['TCodeCompletionCodeTool.AddMethods ',i,' CleanProcTxt=',CleanProcCode,' FullProcTxt=',FullProcCode]);
|
||||
@ -5746,6 +5752,7 @@ begin
|
||||
CleanProcCode:=NodeExt.Txt;
|
||||
FullProcCode:=NodeExt.ExtTxt1;
|
||||
ProcName:=NodeExt.ExtTxt2;
|
||||
ProcCode:=NodeExt.ExtTxt3;
|
||||
VisibilityDesc:=TCodeTreeNodeDesc(NodeExt.Flags);
|
||||
case VisibilityDesc of
|
||||
ctnClassPrivate: NewClassPart:=ncpPrivateProcs;
|
||||
@ -5754,13 +5761,20 @@ begin
|
||||
ctnClassPublished: NewClassPart:=ncpPublishedProcs;
|
||||
else NewClassPart:=ncpPublicProcs;
|
||||
end;
|
||||
AddClassInsertion(CleanProcCode,FullProcCode,ProcName,NewClassPart);
|
||||
|
||||
AddClassInsertion(CleanProcCode,FullProcCode,ProcName,NewClassPart,nil,
|
||||
ProcCode);
|
||||
|
||||
AVLNode:=NewMethods.FindSuccessor(AVLNode);
|
||||
end;
|
||||
|
||||
// extend class declaration
|
||||
if not InsertAllNewClassParts then exit;
|
||||
|
||||
// create missing method bodies
|
||||
if not CreateMissingProcBodies then exit;
|
||||
|
||||
// apply changes
|
||||
if not InsertAllNewClassParts then exit;
|
||||
if not SourceChangeCache.Apply then
|
||||
RaiseException(ctsUnableToApplyChanges);
|
||||
|
||||
|
@ -390,7 +390,8 @@ type
|
||||
var Identifier: string): boolean;
|
||||
function IdentItemCheckHasChilds(IdentItem: TIdentifierListItem): boolean;
|
||||
function FindAbstractMethods(Code: TCodeBuffer; X,Y: integer;
|
||||
out ListOfPCodeXYPosition: TFPList): boolean;
|
||||
out ListOfPCodeXYPosition: TFPList;
|
||||
SkipAbstractsInStartClass: boolean = false): boolean;
|
||||
|
||||
// rename identifier
|
||||
function FindReferences(IdentifierCode: TCodeBuffer;
|
||||
@ -1989,7 +1990,7 @@ begin
|
||||
end;
|
||||
|
||||
function TCodeToolManager.FindAbstractMethods(Code: TCodeBuffer; X, Y: integer;
|
||||
out ListOfPCodeXYPosition: TFPList): boolean;
|
||||
out ListOfPCodeXYPosition: TFPList; SkipAbstractsInStartClass: boolean): boolean;
|
||||
var
|
||||
CursorPos: TCodeXYPosition;
|
||||
begin
|
||||
@ -2003,7 +2004,8 @@ begin
|
||||
CursorPos.Y:=Y;
|
||||
CursorPos.Code:=Code;
|
||||
try
|
||||
Result:=FCurCodeTool.FindAbstractMethods(CursorPos,ListOfPCodeXYPosition);
|
||||
Result:=FCurCodeTool.FindAbstractMethods(CursorPos,ListOfPCodeXYPosition,
|
||||
SkipAbstractsInStartClass);
|
||||
except
|
||||
on e: Exception do Result:=HandleException(e);
|
||||
end;
|
||||
|
@ -72,7 +72,7 @@ begin
|
||||
raise Exception.Create('loading failed '+Filename);
|
||||
|
||||
// find abstract methods
|
||||
if CodeToolBoss.FindAbstractMethods(Code,X,Y,ListOfPCodeXYPosition)
|
||||
if CodeToolBoss.FindAbstractMethods(Code,X,Y,ListOfPCodeXYPosition,true)
|
||||
then begin
|
||||
writeln('FindAbstractMethods succeeded: ');
|
||||
if ListOfPCodeXYPosition<>nil then begin
|
||||
@ -92,7 +92,6 @@ begin
|
||||
end else begin
|
||||
writeln('AddMethods failed: ',CodeToolBoss.ErrorMessage);
|
||||
end;
|
||||
|
||||
except
|
||||
on E: Exception do begin
|
||||
writeln(E.Message);
|
||||
|
@ -307,7 +307,8 @@ type
|
||||
function FindCodeContext(const CursorPos: TCodeXYPosition;
|
||||
out CodeContexts: TCodeContextInfo): boolean;
|
||||
function FindAbstractMethods(const CursorPos: TCodeXYPosition;
|
||||
out ListOfPCodeXYPosition: TFPList): boolean;
|
||||
out ListOfPCodeXYPosition: TFPList;
|
||||
SkipAbstractsInStartClass: boolean = false): boolean;
|
||||
end;
|
||||
|
||||
const
|
||||
@ -1657,8 +1658,8 @@ begin
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.FindAbstractMethods(
|
||||
const CursorPos: TCodeXYPosition; out ListOfPCodeXYPosition: TFPList
|
||||
): boolean;
|
||||
const CursorPos: TCodeXYPosition; out ListOfPCodeXYPosition: TFPList;
|
||||
SkipAbstractsInStartClass: boolean): boolean;
|
||||
var
|
||||
CleanCursorPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
@ -1668,6 +1669,8 @@ var
|
||||
ATool: TFindDeclarationTool;
|
||||
ANode: TCodeTreeNode;
|
||||
ProcXYPos: TCodeXYPosition;
|
||||
Skip: Boolean;
|
||||
ClassNode: TCodeTreeNode;
|
||||
begin
|
||||
Result:=false;
|
||||
ListOfPCodeXYPosition:=nil;
|
||||
@ -1690,10 +1693,11 @@ begin
|
||||
DebugLn(['TIdentCompletionTool.FindAbstractMethods cursor not in a class']);
|
||||
exit;
|
||||
end;
|
||||
ClassNode:=CursorNode;
|
||||
|
||||
Params:=TFindDeclarationParams.Create;
|
||||
// gather all identifiers in context
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.ContextNode:=ClassNode;
|
||||
Params.SetIdentifier(Self,nil,@CollectMethods);
|
||||
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
|
||||
InitFoundMethods;
|
||||
@ -1706,7 +1710,12 @@ begin
|
||||
ANode:=NodeExt.Node;
|
||||
ATool:=TFindDeclarationTool(NodeExt.Data);
|
||||
//DebugLn(['TIdentCompletionTool.FindAbstractMethods ',NodeExt.Txt,' ',ATool.ProcNodeHasSpecifier(ANode,psABSTRACT)]);
|
||||
if ATool.ProcNodeHasSpecifier(ANode,psABSTRACT) then begin
|
||||
Skip:=false;
|
||||
if not ATool.ProcNodeHasSpecifier(ANode,psABSTRACT) then
|
||||
Skip:=true;
|
||||
if SkipAbstractsInStartClass and (ANode.HasAsParent(ClassNode)) then
|
||||
Skip:=true;
|
||||
if not Skip then begin
|
||||
if not ATool.CleanPosToCaret(ANode.StartPos,ProcXYPos) then
|
||||
raise Exception.Create('TIdentCompletionTool.FindAbstractMethods inconsistency');
|
||||
AddCodePosition(ListOfPCodeXYPosition,ProcXYPos);
|
||||
|
Loading…
Reference in New Issue
Block a user