mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-07 16:18:46 +02:00
codetools: class completion: check if vars exists ancestors, bug #1189, patch from Ondrej Pokorny
git-svn-id: trunk@50006 -
This commit is contained in:
parent
db1651b90f
commit
4f6fa03e6f
@ -445,7 +445,12 @@ function TCodeCompletionCodeTool.ProcExistsInCodeCompleteClass(
|
|||||||
// NameAndParams should be uppercase and contains the proc name and the
|
// NameAndParams should be uppercase and contains the proc name and the
|
||||||
// parameter list without names and default values
|
// parameter list without names and default values
|
||||||
// and should not contain any comments and no result type
|
// and should not contain any comments and no result type
|
||||||
var ANodeExt: TCodeTreeNodeExtension;
|
var
|
||||||
|
ANodeExt: TCodeTreeNodeExtension;
|
||||||
|
Params: TFindDeclarationParams;
|
||||||
|
ClassNode, CompletingChildNode: TCodeTreeNode;
|
||||||
|
Tool: TFindDeclarationTool;
|
||||||
|
Vis: TClassSectionVisibility;
|
||||||
begin
|
begin
|
||||||
Result:=false;
|
Result:=false;
|
||||||
// search in new nodes, which will be inserted
|
// search in new nodes, which will be inserted
|
||||||
@ -455,9 +460,29 @@ begin
|
|||||||
exit(true);
|
exit(true);
|
||||||
ANodeExt:=ANodeExt.Next;
|
ANodeExt:=ANodeExt.Next;
|
||||||
end;
|
end;
|
||||||
// ToDo: check ancestor procs too
|
|
||||||
// search in current class
|
// search in current class
|
||||||
Result:=(FindProcNode(FCompletingFirstEntryNode,NameAndParamsUpCase,mgMethod,[phpInUpperCase])<>nil);
|
Result:=(FindProcNode(FCompletingFirstEntryNode,NameAndParamsUpCase,mgMethod,[phpInUpperCase])<>nil);
|
||||||
|
if not Result then
|
||||||
|
begin
|
||||||
|
//search in ancestor classes
|
||||||
|
Params:=TFindDeclarationParams.Create;
|
||||||
|
try
|
||||||
|
ClassNode:=CodeCompleteClassNode;
|
||||||
|
Tool:=Self;
|
||||||
|
while not Result and Tool.FindAncestorOfClass(ClassNode,Params,True) do begin
|
||||||
|
Tool:=Params.NewCodeTool;
|
||||||
|
ClassNode:=Params.NewNode;
|
||||||
|
CompletingChildNode:=GetFirstClassIdentifier(ClassNode);
|
||||||
|
if Tool=Self then
|
||||||
|
Vis := csvPrivateAndHigher
|
||||||
|
else
|
||||||
|
Vis := csvProtectedAndHigher;
|
||||||
|
Result := (Tool.FindProcNode(CompletingChildNode,NameAndParamsUpCase,mgMethod,[phpInUpperCase], Vis)<>nil);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Params.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCodeCompletionCodeTool.SetCodeCompleteClassNode(const AClassNode: TCodeTreeNode);
|
procedure TCodeCompletionCodeTool.SetCodeCompleteClassNode(const AClassNode: TCodeTreeNode);
|
||||||
@ -556,7 +581,12 @@ end;
|
|||||||
|
|
||||||
function TCodeCompletionCodeTool.VarExistsInCodeCompleteClass(
|
function TCodeCompletionCodeTool.VarExistsInCodeCompleteClass(
|
||||||
const UpperName: string): boolean;
|
const UpperName: string): boolean;
|
||||||
var ANodeExt: TCodeTreeNodeExtension;
|
var
|
||||||
|
ANodeExt: TCodeTreeNodeExtension;
|
||||||
|
Params: TFindDeclarationParams;
|
||||||
|
ClassNode, CompletingChildNode: TCodeTreeNode;
|
||||||
|
Tool: TFindDeclarationTool;
|
||||||
|
Vis: TClassSectionVisibility;
|
||||||
begin
|
begin
|
||||||
Result:=false;
|
Result:=false;
|
||||||
// search in new nodes, which will be inserted
|
// search in new nodes, which will be inserted
|
||||||
@ -566,9 +596,29 @@ begin
|
|||||||
exit(true);
|
exit(true);
|
||||||
ANodeExt:=ANodeExt.Next;
|
ANodeExt:=ANodeExt.Next;
|
||||||
end;
|
end;
|
||||||
// ToDo: check ancestor vars too
|
|
||||||
// search in current class
|
// search in current class
|
||||||
Result:=(FindVarNode(FCompletingFirstEntryNode,UpperName)<>nil);
|
Result:=(FindVarNode(FCompletingFirstEntryNode,UpperName)<>nil);
|
||||||
|
if not Result then
|
||||||
|
begin
|
||||||
|
//search in ancestor classes
|
||||||
|
Params:=TFindDeclarationParams.Create;
|
||||||
|
try
|
||||||
|
ClassNode:=CodeCompleteClassNode;
|
||||||
|
Tool:=Self;
|
||||||
|
while not Result and Tool.FindAncestorOfClass(ClassNode,Params,True) do begin
|
||||||
|
Tool:=Params.NewCodeTool;
|
||||||
|
ClassNode:=Params.NewNode;
|
||||||
|
CompletingChildNode:=GetFirstClassIdentifier(ClassNode);
|
||||||
|
if Tool=Self then
|
||||||
|
Vis := csvPrivateAndHigher
|
||||||
|
else
|
||||||
|
Vis := csvProtectedAndHigher;
|
||||||
|
Result := (Tool.FindVarNode(CompletingChildNode,UpperName,Vis)<>nil);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Params.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCodeCompletionCodeTool.AddClassInsertion(
|
procedure TCodeCompletionCodeTool.AddClassInsertion(
|
||||||
|
@ -66,6 +66,12 @@ type
|
|||||||
Group: TPascalMethodGroup;
|
Group: TPascalMethodGroup;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TClassSectionVisibility = (
|
||||||
|
csvEverything,//same class same unit
|
||||||
|
csvPrivateAndHigher,//same unit different class
|
||||||
|
csvProtectedAndHigher,//ancestor class different unit
|
||||||
|
csvPublicAndHigher);//other class other unit
|
||||||
|
|
||||||
TOnEachPRIdentifier = procedure(Sender: TPascalParserTool;
|
TOnEachPRIdentifier = procedure(Sender: TPascalParserTool;
|
||||||
IdentifierCleanPos: integer; Range: TEPRIRange;
|
IdentifierCleanPos: integer; Range: TEPRIRange;
|
||||||
Node: TCodeTreeNode; Data: Pointer; var Abort: boolean) of object;
|
Node: TCodeTreeNode; Data: Pointer; var Abort: boolean) of object;
|
||||||
@ -141,9 +147,9 @@ type
|
|||||||
function GetProcNameIdentifier(ProcNode: TCodeTreeNode): PChar;
|
function GetProcNameIdentifier(ProcNode: TCodeTreeNode): PChar;
|
||||||
function FindProcNode(StartNode: TCodeTreeNode; const AProcHead: string;
|
function FindProcNode(StartNode: TCodeTreeNode; const AProcHead: string;
|
||||||
AProcSpecType: TPascalMethodGroup;
|
AProcSpecType: TPascalMethodGroup;
|
||||||
Attr: TProcHeadAttributes): TCodeTreeNode; overload;
|
Attr: TProcHeadAttributes; Visibility: TClassSectionVisibility = csvEverything): TCodeTreeNode; overload;
|
||||||
function FindProcNode(StartNode: TCodeTreeNode; const AProcHead: TPascalMethodHeader;
|
function FindProcNode(StartNode: TCodeTreeNode; const AProcHead: TPascalMethodHeader;
|
||||||
Attr: TProcHeadAttributes): TCodeTreeNode; overload;
|
Attr: TProcHeadAttributes; Visibility: TClassSectionVisibility = csvEverything): TCodeTreeNode; overload;
|
||||||
function FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
|
function FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
|
||||||
Attr: TProcHeadAttributes = [phpWithoutClassKeyword,phpWithoutClassName]
|
Attr: TProcHeadAttributes = [phpWithoutClassKeyword,phpWithoutClassName]
|
||||||
): TCodeTreeNode;
|
): TCodeTreeNode;
|
||||||
@ -216,13 +222,15 @@ type
|
|||||||
function IsClassNode(Node: TCodeTreeNode): boolean; // class, not object
|
function IsClassNode(Node: TCodeTreeNode): boolean; // class, not object
|
||||||
function FindInheritanceNode(ClassNode: TCodeTreeNode): TCodeTreeNode;
|
function FindInheritanceNode(ClassNode: TCodeTreeNode): TCodeTreeNode;
|
||||||
function FindHelperForNode(HelperNode: TCodeTreeNode): TCodeTreeNode;
|
function FindHelperForNode(HelperNode: TCodeTreeNode): TCodeTreeNode;
|
||||||
|
function IdentNodeIsInVisibleClassSection(Node: TCodeTreeNode; Visibility: TClassSectionVisibility): Boolean;
|
||||||
|
|
||||||
// records
|
// records
|
||||||
function ExtractRecordCaseType(RecordCaseNode: TCodeTreeNode): string;
|
function ExtractRecordCaseType(RecordCaseNode: TCodeTreeNode): string;
|
||||||
|
|
||||||
// variables, types
|
// variables, types
|
||||||
function FindVarNode(StartNode: TCodeTreeNode;
|
function FindVarNode(StartNode: TCodeTreeNode;
|
||||||
const UpperVarName: string): TCodeTreeNode;
|
const UpperVarName: string;
|
||||||
|
Visibility: TClassSectionVisibility = csvEverything): TCodeTreeNode;
|
||||||
function FindTypeNodeOfDefinition(
|
function FindTypeNodeOfDefinition(
|
||||||
DefinitionNode: TCodeTreeNode): TCodeTreeNode;
|
DefinitionNode: TCodeTreeNode): TCodeTreeNode;
|
||||||
function NodeIsPartOfTypeDefinition(ANode: TCodeTreeNode): boolean;
|
function NodeIsPartOfTypeDefinition(ANode: TCodeTreeNode): boolean;
|
||||||
@ -911,7 +919,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TPascalReaderTool.FindProcNode(StartNode: TCodeTreeNode;
|
function TPascalReaderTool.FindProcNode(StartNode: TCodeTreeNode;
|
||||||
const AProcHead: TPascalMethodHeader; Attr: TProcHeadAttributes): TCodeTreeNode;
|
const AProcHead: TPascalMethodHeader; Attr: TProcHeadAttributes;
|
||||||
|
Visibility: TClassSectionVisibility): TCodeTreeNode;
|
||||||
// search in all next brothers for a Procedure Node with the Name ProcName
|
// search in all next brothers for a Procedure Node with the Name ProcName
|
||||||
// if there are no further brothers and the parent is a section node
|
// if there are no further brothers and the parent is a section node
|
||||||
// ( e.g. 'interface', 'implementation', ...) or a class visibility node
|
// ( e.g. 'interface', 'implementation', ...) or a class visibility node
|
||||||
@ -928,7 +937,9 @@ begin
|
|||||||
if (not ((phpIgnoreForwards in Attr)
|
if (not ((phpIgnoreForwards in Attr)
|
||||||
and ((Result.SubDesc and ctnsForwardDeclaration)>0)))
|
and ((Result.SubDesc and ctnsForwardDeclaration)>0)))
|
||||||
and (not ((phpIgnoreProcsWithBody in Attr)
|
and (not ((phpIgnoreProcsWithBody in Attr)
|
||||||
and (FindProcBody(Result)<>nil))) then
|
and (FindProcBody(Result)<>nil)))
|
||||||
|
and (not InClass or IdentNodeIsInVisibleClassSection(Result, Visibility))
|
||||||
|
then
|
||||||
begin
|
begin
|
||||||
CurProcHead:=ExtractProcHeadWithGroup(Result,Attr);
|
CurProcHead:=ExtractProcHeadWithGroup(Result,Attr);
|
||||||
//DebugLn(['TPascalReaderTool.FindProcNode B "',CurProcHead,'" =? "',AProcHead,'" Result=',CompareTextIgnoringSpace(CurProcHead,AProcHead,false)]);
|
//DebugLn(['TPascalReaderTool.FindProcNode B "',CurProcHead,'" =? "',AProcHead,'" Result=',CompareTextIgnoringSpace(CurProcHead,AProcHead,false)]);
|
||||||
@ -948,13 +959,13 @@ end;
|
|||||||
|
|
||||||
function TPascalReaderTool.FindProcNode(StartNode: TCodeTreeNode;
|
function TPascalReaderTool.FindProcNode(StartNode: TCodeTreeNode;
|
||||||
const AProcHead: string; AProcSpecType: TPascalMethodGroup;
|
const AProcHead: string; AProcSpecType: TPascalMethodGroup;
|
||||||
Attr: TProcHeadAttributes): TCodeTreeNode;
|
Attr: TProcHeadAttributes; Visibility: TClassSectionVisibility): TCodeTreeNode;
|
||||||
var
|
var
|
||||||
ProcHead: TPascalMethodHeader;
|
ProcHead: TPascalMethodHeader;
|
||||||
begin
|
begin
|
||||||
ProcHead.Name := AProcHead;
|
ProcHead.Name := AProcHead;
|
||||||
ProcHead.Group := AProcSpecType;
|
ProcHead.Group := AProcSpecType;
|
||||||
Result := FindProcNode(StartNode, ProcHead, Attr);
|
Result := FindProcNode(StartNode, ProcHead, Attr, Visibility);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPascalReaderTool.FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
|
function TPascalReaderTool.FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
|
||||||
@ -2070,7 +2081,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TPascalReaderTool.FindVarNode(StartNode: TCodeTreeNode;
|
function TPascalReaderTool.FindVarNode(StartNode: TCodeTreeNode;
|
||||||
const UpperVarName: string): TCodeTreeNode;
|
const UpperVarName: string; Visibility: TClassSectionVisibility
|
||||||
|
): TCodeTreeNode;
|
||||||
var
|
var
|
||||||
InClass: Boolean;
|
InClass: Boolean;
|
||||||
begin
|
begin
|
||||||
@ -2078,6 +2090,7 @@ begin
|
|||||||
InClass:=FindClassOrInterfaceNode(StartNode)<>nil;
|
InClass:=FindClassOrInterfaceNode(StartNode)<>nil;
|
||||||
while Result<>nil do begin
|
while Result<>nil do begin
|
||||||
if (Result.Desc=ctnVarDefinition)
|
if (Result.Desc=ctnVarDefinition)
|
||||||
|
and (not InClass or IdentNodeIsInVisibleClassSection(Result, Visibility))
|
||||||
and (CompareNodeIdentChars(Result,UpperVarName)=0) then
|
and (CompareNodeIdentChars(Result,UpperVarName)=0) then
|
||||||
exit;
|
exit;
|
||||||
if InClass then
|
if InClass then
|
||||||
@ -2487,6 +2500,26 @@ begin
|
|||||||
Result:=ctnNone;
|
Result:=ctnNone;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPascalReaderTool.IdentNodeIsInVisibleClassSection(
|
||||||
|
Node: TCodeTreeNode; Visibility: TClassSectionVisibility): Boolean;
|
||||||
|
begin
|
||||||
|
if Visibility = csvEverything then
|
||||||
|
Result := True
|
||||||
|
else
|
||||||
|
if (Node.Parent<>nil) then
|
||||||
|
case Visibility of
|
||||||
|
//csvAbovePrivate: todo: add strict private and strict protected (should be registered as new sections)
|
||||||
|
csvProtectedAndHigher:
|
||||||
|
Result := not(Node.Parent.Desc = ctnClassPrivate);//todo: add strict private
|
||||||
|
csvPublicAndHigher:
|
||||||
|
Result := not(Node.Parent.Desc in [ctnClassPrivate, ctnClassProtected]);//todo: strict private and strict protected
|
||||||
|
else
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPascalReaderTool.ExtractProcedureGroup(ProcNode: TCodeTreeNode
|
function TPascalReaderTool.ExtractProcedureGroup(ProcNode: TCodeTreeNode
|
||||||
): TPascalMethodGroup;
|
): TPascalMethodGroup;
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user