codetools: implemented AddMethods

git-svn-id: trunk@13204 -
This commit is contained in:
mattias 2007-12-07 15:30:22 +00:00
parent 7cac0aa984
commit 6060a047ed
5 changed files with 104 additions and 26 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);