diff --git a/components/codetools/codecompletiontool.pas b/components/codetools/codecompletiontool.pas index b774ff838b..e555a9d942 100644 --- a/components/codetools/codecompletiontool.pas +++ b/components/codetools/codecompletiontool.pas @@ -172,6 +172,10 @@ type OldTopLine: integer; CursorNode: TCodeTreeNode; var NewPos: TCodeXYPosition; var NewTopLine: integer; SourceChangeCache: TSourceChangeCache): boolean; + function CompleteMethod(CleanCursorPos, OldTopLine: integer; + CursorNode: TCodeTreeNode; + var NewPos: TCodeXYPosition; var NewTopLine: integer; + SourceChangeCache: TSourceChangeCache): boolean; protected property CodeCompleteClassNode: TCodeTreeNode read FCodeCompleteClassNode write SetCodeCompleteClassNode; @@ -325,7 +329,7 @@ procedure TCodeCompletionCodeTool.AddClassInsertion( var NewInsert, InsertPos, LastInsertPos: TCodeTreeNodeExtension; begin {$IFDEF CTDEBUG} - DebugLn('[TCodeCompletionCodeTool.AddClassInsertion] ',CleanDef,',',Def,',',Identifiername); + DebugLn('[TCodeCompletionCodeTool.AddClassInsertion] CleanDef="',CleanDef,'" Def="',Def,'" Identifiername="',Identifiername,'" Body="',Body,'"'); {$ENDIF} NewInsert:=NodeExtMemManager.NewNode; with NewInsert do begin @@ -991,6 +995,72 @@ begin NewType,NewPos,NewTopLine,SourceChangeCache); end; +function TCodeCompletionCodeTool.CompleteMethod( + CleanCursorPos, OldTopLine: integer; + CursorNode: TCodeTreeNode; + var NewPos: TCodeXYPosition; var NewTopLine: integer; + SourceChangeCache: TSourceChangeCache): boolean; +var + CurClassName: String; + ProcNode: TCodeTreeNode; + CleanProcCode: String; + ProcCode: String; + ProcName: String; + OldCodePos: TCodePosition; +begin + Result:=false; + + // check if cursor in a method + ProcNode:=CursorNode.GetNodeOfType(ctnProcedure); + if (ProcNode=nil) and (CursorNode.Desc=ctnProcedure) then + ProcNode:=CursorNode; + if (ProcNode=nil) or (ProcNode.Desc<>ctnProcedure) + or ((ProcNode.SubDesc and ctnsForwardDeclaration)<>0) + or (not NodeIsMethodBody(ProcNode)) then begin + exit; + end; + + // find corresponding class declaration + CurClassName:=ExtractClassNameOfProcNode(ProcNode); + if CurClassName='' then begin + DebugLn(['CompleteMethod ExtractClassNameOfProcNode failed']); + exit; + end; + //DebugLn(['CompleteMethod CurClassName=',CurClassName]); + CodeCompleteClassNode:=FindClassNodeInUnit(CurClassName,true,false,false,true); + + // check if method declaration already exists + ProcName:=ExtractProcName(ProcNode,[phpWithoutClassName]); + CleanProcCode:=ExtractProcHead(ProcNode, + [phpWithoutClassKeyword,phpWithoutClassName,phpInUpperCase]); + if ProcExistsInCodeCompleteClass(CleanProcCode) then begin + // proc exists already + MoveCursorToCleanPos(CleanCursorPos); + RaiseExceptionFmt(ctsIdentifierAlreadyDefined,[ProcName]); + end; + + // store old cursor position + if not CleanPosToCodePos(CleanCursorPos,OldCodePos) then begin + RaiseException('TCodeCompletionCodeTool.AddLocalVariable Internal Error: ' + +'CleanPosToCodePos'); + end; + + CodeCompleteSrcChgCache:=SourceChangeCache; + + // add method declaration + ProcCode:=ExtractProcHead(ProcNode, + [phpWithStart,phpWithoutClassName,phpWithVarModifiers,phpWithParameterNames, + phpWithDefaultValues,phpWithResultType,phpWithCallingSpecs]); + AddClassInsertion(CleanProcCode,ProcCode,ProcName,ncpPrivateProcs); + + // apply changes + Result:=ApplyClassCompletion; + + // adjust cursor position + AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine); + //DebugLn(['TCodeCompletionCodeTool.CompleteMethod END OldCodePos.P=',OldCodePos.P,' OldTopLine=',OldTopLine,' NewPos=',DbgsCXY(NewPos),' NewTopLine=',NewTopLine]); +end; + function TCodeCompletionCodeTool.AddPublishedVariable(const UpperClassName, VarName, VarType: string; SourceChangeCache: TSourceChangeCache): boolean; begin @@ -1004,7 +1074,7 @@ begin CodeCompleteClassNode:=FindClassNodeInInterface(UpperClassName,true,false,true); CodeCompleteSrcChgCache:=SourceChangeCache; // check if variable already exists - if VarExistsInCodeCompleteClass(UpperCaseStr(VarName)) then begin + if not VarExistsInCodeCompleteClass(UpperCaseStr(VarName)) then begin end else begin AddClassInsertion(UpperCaseStr(VarName), @@ -1028,7 +1098,7 @@ begin BuildTree(false); if not EndOfSourceFound then exit; if (SourceChangeCache=nil) or (Scanner=nil) then exit; - ClassNode:=FindClassNodeInInterface(UpperClassName,true,false,true); + ClassNode:=FindClassNodeInUnit(UpperClassName,true,false,false,true); if (ClassNode=nil) then exit; CodeCompleteClassNode:=ClassNode; CodeCompleteSrcChgCache:=SourceChangeCache; @@ -2554,7 +2624,7 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition; var CleanCursorPos, Indent, insertPos: integer; CursorNode, ProcNode, ImplementationNode, SectionNode, AClassNode, ANode: TCodeTreeNode; - ProcCode: string; + OldCleanCursorPos: LongInt; procedure CompleteClass; var @@ -2663,11 +2733,6 @@ var CleanCursorPos, Indent, insertPos: integer; end; end; - procedure CompleteMethod; - begin - // ToDo - end; - procedure CompleteForwardProcs; // add proc bodies for forward procs var @@ -2676,6 +2741,7 @@ var CleanCursorPos, Indent, insertPos: integer; StartProcNode: TCodeTreeNode; CurProcNode: TCodeTreeNode; EndProcNode: TCodeTreeNode; + ProcCode: String; begin {$IFDEF CTDEBUG} DebugLn('TCodeCompletionCodeTool.CompleteCode in a forward procedure ... '); @@ -3079,10 +3145,13 @@ var CleanCursorPos, Indent, insertPos: integer; // var NewPos: TCodeXYPosition; var NewTopLine: integer; // SourceChangeCache: TSourceChangeCache): boolean; begin + //DebugLn(['TCodeCompletionCodeTool.CompleteCode CursorPos=',DbgsCXY(CursorPos),' OldTopLine=',OldTopLine]); + Result:=false; if (SourceChangeCache=nil) then RaiseException('need a SourceChangeCache'); BuildTreeAndGetCleanPos(trAll,CursorPos, CleanCursorPos,[]); + OldCleanCursorPos:=CleanCursorPos; NewPos:=CleanCodeXYPosition; NewTopLine:=0; @@ -3136,25 +3205,19 @@ begin if Result then exit; // test if Local variable assignment - Result:=CompleteLocalVariableAssignment(CleanCursorPos,OldTopLine,CursorNode, - NewPos,NewTopLine,SourceChangeCache); + Result:=CompleteLocalVariableAssignment(CleanCursorPos,OldTopLine, + CursorNode,NewPos,NewTopLine,SourceChangeCache); if Result then exit; // test if undeclared local variable as parameter - Result:=CompleteLocalVariableAsParameter(CleanCursorPos,OldTopLine,CursorNode, - NewPos,NewTopLine,SourceChangeCache); + Result:=CompleteLocalVariableAsParameter(CleanCursorPos,OldTopLine, + CursorNode,NewPos,NewTopLine,SourceChangeCache); if Result then exit; // test if method body - ProcNode:=CursorNode.GetNodeOfType(ctnProcedure); - if (ProcNode=nil) and (CursorNode.Desc=ctnProcedure) then - ProcNode:=CursorNode; - if (ProcNode<>nil) and (ProcNode.Desc=ctnProcedure) - and ((ProcNode.SubDesc and ctnsForwardDeclaration)=0) - and NodeIsMethodBody(ProcNode) then begin - CompleteMethod; - exit; - end; + Result:=CompleteMethod(OldCleanCursorPos,OldTopLine,CursorNode, + NewPos,NewTopLine,SourceChangeCache); + if Result then exit; {$IFDEF CTDEBUG} DebugLn('TCodeCompletionCodeTool.CompleteCode nothing to complete ... '); diff --git a/components/codetools/finddeclarationtool.pas b/components/codetools/finddeclarationtool.pas index 08c4f2d204..986dd9a24a 100644 --- a/components/codetools/finddeclarationtool.pas +++ b/components/codetools/finddeclarationtool.pas @@ -4466,29 +4466,25 @@ begin Result:=FindIdentifierInContext(Params); Params.Load(OldInput); + if (Params.NewCodeTool<>Self) then Result:=false; + // save result in cache if Params.Flags*[fdfCollect,fdfDoNotCache]=[] then begin if FInterfaceIdentifierCache=nil then FInterfaceIdentifierCache:=TInterfaceIdentifierCache.Create(Self); - if Result and (Params.NewCodeTool=Self) then begin + if Result then begin // identifier exists in interface - if ([fdfDoNotCache,fdfCollect]*Params.Flags=[]) - and ([fodDoNotCache]*Params.NewFlags=[]) then begin - if (Params.NewNode<>nil) and (Params.NewNode.Desc=ctnProcedure) then begin - //DebugLn('NOTE: TFindDeclarationTool.FindIdentifierInInterface Node is proc'); - // ToDo: add param list to cache - // -> do not cache - Result:=false; - end else - FInterfaceIdentifierCache.Add(OldInput.Identifier,Params.NewNode, - Params.NewCleanPos); + if (Params.NewNode<>nil) and (Params.NewNode.Desc=ctnProcedure) then begin + //DebugLn('NOTE: TFindDeclarationTool.FindIdentifierInInterface Node is proc'); + // ToDo: add param list to cache + // -> do not cache end else begin - // do not save proc identifiers or collection results + FInterfaceIdentifierCache.Add(OldInput.Identifier,Params.NewNode, + Params.NewCleanPos); end; end else begin // identifier does not exist in this interface FInterfaceIdentifierCache.Add(OldInput.Identifier,nil,-1); - Result:=false; end; end; end; diff --git a/components/codetools/pascalparsertool.pas b/components/codetools/pascalparsertool.pas index 5d26447ef1..f45e9d2b5d 100644 --- a/components/codetools/pascalparsertool.pas +++ b/components/codetools/pascalparsertool.pas @@ -3684,8 +3684,7 @@ begin else ExtractMemStream.Write(Src[LastAtomEndPos], CurPos.StartPos-LastAtomEndPos); - end else if (CurPos.StartPos>LastAtomEndPos) - and (ExtractMemStream.Position>0) then + end else if (ExtractMemStream.Position>0) then begin // some code was skipped // -> check if a space must be inserted diff --git a/ide/main.pp b/ide/main.pp index 5c1258d5ea..de0f3f844c 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -10530,6 +10530,12 @@ var NewUnitInfo: TUnitInfo; begin Result:=mrCancel; + if NewSource=nil then begin + DebugLn(['TMainIDE.DoJumpToCodePos ERROR: missing NewSource']); + DumpStack; + exit; + end; + if (ActiveSrcEdit=nil) or (ActiveUnitInfo=nil) then GetCurrentUnit(ActiveSrcEdit,ActiveUnitInfo); if AddJumpPoint then begin @@ -10554,7 +10560,7 @@ begin if NewY<1 then NewY:=1; if NewTopLine<1 then NewTopLine:=Max(1,NewY-(NewSrcEdit.EditorComponent.LinesInWindow div 2)); - //writeln('[TMainIDE.DoJumpToCodePos] ',NewX,',',NewY,',',NewTopLine); + //debugln(['[TMainIDE.DoJumpToCodePos] ',NewX,',',NewY,',',NewTopLine]); with NewSrcEdit.EditorComponent do begin MoveLogicalCaretIgnoreEOL(Point(NewX,NewY)); BlockBegin:=LogicalCaretXY;