mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-29 09:10:20 +02:00
codetools: code completion: operator enumerator current
git-svn-id: trunk@22429 -
This commit is contained in:
parent
13712e5d89
commit
ef08824411
@ -257,6 +257,13 @@ ResourceString
|
|||||||
ctsFileIsNotExecutable = '%s is not executable';
|
ctsFileIsNotExecutable = '%s is not executable';
|
||||||
ctsSrcPathForCompiledUnits = 'src path for compiled units';
|
ctsSrcPathForCompiledUnits = 'src path for compiled units';
|
||||||
ctsTCodeToolManagerConsistencyCheck = 'TCodeToolManager.ConsistencyCheck=%d';
|
ctsTCodeToolManagerConsistencyCheck = 'TCodeToolManager.ConsistencyCheck=%d';
|
||||||
|
ctsFunctionGetEnumeratorNotFoundInThisClass = 'function GetEnumerator not '
|
||||||
|
+'found in this class';
|
||||||
|
ctsFunctionGetEnumeratorNotFoundInThisClass2 = 'function GetEnumerator not '
|
||||||
|
+'found in this class';
|
||||||
|
ctsResultTypeOfFunctionGetEnumeratorNotFound = 'result type of function '
|
||||||
|
+'GetEnumerator not found';
|
||||||
|
ctsPropertyCurrentNotFound = 'property Current not found';
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
@ -477,6 +477,7 @@ type
|
|||||||
OnIdentifierFound: TOnIdentifierFound;
|
OnIdentifierFound: TOnIdentifierFound;
|
||||||
IdentifierTool: TFindDeclarationTool;
|
IdentifierTool: TFindDeclarationTool;
|
||||||
FoundProc: PFoundProc;
|
FoundProc: PFoundProc;
|
||||||
|
Data: Pointer;
|
||||||
// global params
|
// global params
|
||||||
OnTopLvlIdentifierFound: TOnIdentifierFound;
|
OnTopLvlIdentifierFound: TOnIdentifierFound;
|
||||||
// results:
|
// results:
|
||||||
@ -535,6 +536,13 @@ type
|
|||||||
);
|
);
|
||||||
TFindDeclarationListFlags = set of TFindDeclarationListFlag;
|
TFindDeclarationListFlags = set of TFindDeclarationListFlag;
|
||||||
|
|
||||||
|
TFindOperatorEnumerator = (
|
||||||
|
foeProcNode, // proc node of operator
|
||||||
|
foeResultClassNode, // classnode of result type of operator
|
||||||
|
foeEnumeratorCurrentNode, // function or property with modifier 'enumerator Current'
|
||||||
|
foeEnumeratorCurrentExprType // expression type of 'enumerator Current'
|
||||||
|
);
|
||||||
|
|
||||||
const
|
const
|
||||||
DefaultFindSmartFlags = [fsfIncludeDirective];
|
DefaultFindSmartFlags = [fsfIncludeDirective];
|
||||||
|
|
||||||
@ -648,6 +656,13 @@ type
|
|||||||
out ExprType: TExpressionType): string;
|
out ExprType: TExpressionType): string;
|
||||||
function FindEnumeratorOfClass(ClassNode: TCodeTreeNode;
|
function FindEnumeratorOfClass(ClassNode: TCodeTreeNode;
|
||||||
ExceptionOnNotFound: boolean; out ExprType: TExpressionType): boolean;
|
ExceptionOnNotFound: boolean; out ExprType: TExpressionType): boolean;
|
||||||
|
function FindOperatorEnumerator(Node: TCodeTreeNode;
|
||||||
|
ExprType: TExpressionType; Need: TFindOperatorEnumerator;
|
||||||
|
out ResultExprType: TExpressionType): boolean;
|
||||||
|
function CheckOperatorEnumerator(Params: TFindDeclarationParams;
|
||||||
|
const FoundContext: TFindContext): TIdentifierFoundResult;
|
||||||
|
function CheckModifierEnumeratorCurrent(Params: TFindDeclarationParams;
|
||||||
|
const FoundContext: TFindContext): TIdentifierFoundResult;
|
||||||
function IsTermEdgedBracket(TermPos: TAtomPosition;
|
function IsTermEdgedBracket(TermPos: TAtomPosition;
|
||||||
out EdgedBracketsStartPos: integer): boolean;
|
out EdgedBracketsStartPos: integer): boolean;
|
||||||
function IsTermNamedPointer(TermPos: TAtomPosition;
|
function IsTermNamedPointer(TermPos: TAtomPosition;
|
||||||
@ -8846,6 +8861,7 @@ function TFindDeclarationTool.FindForInTypeAsString(TermPos: TAtomPosition;
|
|||||||
|
|
||||||
var
|
var
|
||||||
TermExprType: TExpressionType;
|
TermExprType: TExpressionType;
|
||||||
|
OperatorExprType: TExpressionType;
|
||||||
begin
|
begin
|
||||||
ExprType:=CleanExpressionType;
|
ExprType:=CleanExpressionType;
|
||||||
TermExprType:=CleanExpressionType;
|
TermExprType:=CleanExpressionType;
|
||||||
@ -8858,6 +8874,19 @@ begin
|
|||||||
DebugLn('TFindDeclarationTool.FindForInTypeAsString TermExprType=',
|
DebugLn('TFindDeclarationTool.FindForInTypeAsString TermExprType=',
|
||||||
ExprTypeToString(TermExprType));
|
ExprTypeToString(TermExprType));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
// search operator enumerator
|
||||||
|
if FindOperatorEnumerator(CursorNode,TermExprType,foeEnumeratorCurrentExprType,
|
||||||
|
OperatorExprType)
|
||||||
|
then begin
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindForInTypeAsString Operator=',ExprTypeToString(OperatorExprType)]);
|
||||||
|
{$ENDIF}
|
||||||
|
ExprType:=OperatorExprType;
|
||||||
|
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,Params);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// use default enumerators
|
||||||
case TermExprType.Desc of
|
case TermExprType.Desc of
|
||||||
xtContext:
|
xtContext:
|
||||||
begin
|
begin
|
||||||
@ -8950,18 +8979,22 @@ begin
|
|||||||
// search function 'GetEnumerator'
|
// search function 'GetEnumerator'
|
||||||
Params.ContextNode:=ClassNode;
|
Params.ContextNode:=ClassNode;
|
||||||
Params.Flags:=[fdfSearchInAncestors];
|
Params.Flags:=[fdfSearchInAncestors];
|
||||||
if ExceptionOnNotFound then
|
|
||||||
Include(Params.Flags,fdfExceptionOnNotFound);
|
|
||||||
Params.SetIdentifier(Self,'GetEnumerator',nil);
|
Params.SetIdentifier(Self,'GetEnumerator',nil);
|
||||||
//DebugLn(['TFindDeclarationTool.FindEnumeratorOfClass searching GetEnumerator ...']);
|
//DebugLn(['TFindDeclarationTool.FindEnumeratorOfClass searching GetEnumerator ...']);
|
||||||
if not FindIdentifierInContext(Params) then exit;
|
if not FindIdentifierInContext(Params) then begin
|
||||||
|
if ExceptionOnNotFound then begin
|
||||||
|
MoveCursorToCleanPos(ClassNode.StartPos);
|
||||||
|
RaiseException(ctsFunctionGetEnumeratorNotFoundInThisClass);
|
||||||
|
end else
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
ProcTool:=Params.NewCodeTool;
|
ProcTool:=Params.NewCodeTool;
|
||||||
ProcNode:=Params.NewNode;
|
ProcNode:=Params.NewNode;
|
||||||
//DebugLn(['TFindDeclarationTool.FindEnumeratorOfClass Proc']);
|
//DebugLn(['TFindDeclarationTool.FindEnumeratorOfClass Proc']);
|
||||||
if (ProcNode=nil) or (ProcNode.Desc<>ctnProcedure) then begin
|
if (ProcNode=nil) or (ProcNode.Desc<>ctnProcedure) then begin
|
||||||
if ExceptionOnNotFound then begin
|
if ExceptionOnNotFound then begin
|
||||||
MoveCursorToCleanPos(ClassNode.StartPos);
|
MoveCursorToCleanPos(ClassNode.StartPos);
|
||||||
RaiseException('function GetEnumerator not found');
|
RaiseException(ctsFunctionGetEnumeratorNotFoundInThisClass2);
|
||||||
end else
|
end else
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -8974,7 +9007,7 @@ begin
|
|||||||
then begin
|
then begin
|
||||||
if ExceptionOnNotFound then begin
|
if ExceptionOnNotFound then begin
|
||||||
ProcTool.MoveCursorToCleanPos(ProcNode.StartPos);
|
ProcTool.MoveCursorToCleanPos(ProcNode.StartPos);
|
||||||
ProcTool.RaiseException('function GetEnumerator not found');
|
ProcTool.RaiseException(ctsResultTypeOfFunctionGetEnumeratorNotFound);
|
||||||
end else
|
end else
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -8993,7 +9026,7 @@ begin
|
|||||||
if (PropNode=nil) or (PropNode.Desc<>ctnProperty) then begin
|
if (PropNode=nil) or (PropNode.Desc<>ctnProperty) then begin
|
||||||
if ExceptionOnNotFound then begin
|
if ExceptionOnNotFound then begin
|
||||||
EnumeratorContext.Tool.MoveCursorToCleanPos(EnumeratorContext.Node.StartPos);
|
EnumeratorContext.Tool.MoveCursorToCleanPos(EnumeratorContext.Node.StartPos);
|
||||||
RaiseException('property Current not found');
|
RaiseException(ctsPropertyCurrentNotFound);
|
||||||
end else
|
end else
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -9012,6 +9045,162 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.FindOperatorEnumerator(Node: TCodeTreeNode;
|
||||||
|
ExprType: TExpressionType; Need: TFindOperatorEnumerator; out
|
||||||
|
ResultExprType: TExpressionType): boolean;
|
||||||
|
// find a compatible operator overload for 'enumerator' with a parameter
|
||||||
|
// compatible to ExprType
|
||||||
|
// for example:
|
||||||
|
// operator enumerator (AList: TMyList): TMyListEnumerator;
|
||||||
|
var
|
||||||
|
Params: TFindDeclarationParams;
|
||||||
|
OperatorTool: TFindDeclarationTool;
|
||||||
|
OperatorNode: TCodeTreeNode;
|
||||||
|
ClassContext: TFindContext;
|
||||||
|
EnumeratorCurrentTool: TFindDeclarationTool;
|
||||||
|
EnumeratorCurrentNode: TCodeTreeNode;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
ResultExprType:=CleanExpressionType;
|
||||||
|
Params:=TFindDeclarationParams.Create;
|
||||||
|
try
|
||||||
|
// search compatible operator enumerator
|
||||||
|
Params.ContextNode:=Node;
|
||||||
|
Params.Flags:=[fdfSearchInParentNodes];
|
||||||
|
Params.Data:=@ExprType;
|
||||||
|
Params.SetIdentifier(Self,'Enumerator',@CheckOperatorEnumerator);
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator searching operator enumerator ...']);
|
||||||
|
{$ENDIF}
|
||||||
|
if not FindIdentifierInContext(Params) then exit;
|
||||||
|
|
||||||
|
// operator found
|
||||||
|
// now check if it is valid
|
||||||
|
OperatorTool:=Params.NewCodeTool;
|
||||||
|
OperatorNode:=Params.NewNode;
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator Operator="',OperatorTool.ExtractNode(OperatorNode,[]),'"']);
|
||||||
|
{$ENDIF}
|
||||||
|
if Need=foeProcNode then begin
|
||||||
|
ResultExprType.Desc:=xtContext;
|
||||||
|
ResultExprType.Context.Tool:=OperatorTool;
|
||||||
|
ResultExprType.Context.Node:=OperatorNode;
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// search class node
|
||||||
|
Params.Clear;
|
||||||
|
Params.Flags:=[fdfFunctionResult];
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator searching operator result object ...']);
|
||||||
|
{$ENDIF}
|
||||||
|
ClassContext:=OperatorTool.FindBaseTypeOfNode(Params,OperatorNode);
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator ClassContext=',FindContextToString(ClassContext)]);
|
||||||
|
{$ENDIF}
|
||||||
|
case ClassContext.Node.Desc of
|
||||||
|
ctnClass,ctnObject: ;
|
||||||
|
else
|
||||||
|
OperatorTool.MoveCursorToNodeStart(OperatorNode);
|
||||||
|
OperatorTool.RaiseException('operator enumerator result type is not object');
|
||||||
|
end;
|
||||||
|
if Need=foeResultClassNode then begin
|
||||||
|
ResultExprType.Desc:=xtContext;
|
||||||
|
ResultExprType.Context:=ClassContext;
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// search property with modifier enumerator Current
|
||||||
|
Params.Clear;
|
||||||
|
Params.ContextNode:=ClassContext.Node;
|
||||||
|
Params.Flags:=[fdfSearchInAncestors,fdfCollect];
|
||||||
|
Params.SetIdentifier(Self,'',@CheckModifierEnumeratorCurrent);
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator searching enumerator current ...']);
|
||||||
|
{$ENDIF}
|
||||||
|
if not ClassContext.Tool.FindIdentifierInContext(Params) then begin
|
||||||
|
ClassContext.Tool.MoveCursorToNodeStart(ClassContext.Node);
|
||||||
|
ClassContext.Tool.RaiseException('enumerator ''current'' not found');
|
||||||
|
end;
|
||||||
|
EnumeratorCurrentTool:=Params.NewCodeTool;
|
||||||
|
EnumeratorCurrentNode:=Params.NewNode;
|
||||||
|
if Need=foeEnumeratorCurrentNode then begin
|
||||||
|
ResultExprType.Desc:=xtContext;
|
||||||
|
ResultExprType.Context.Tool:=EnumeratorCurrentTool;
|
||||||
|
ResultExprType.Context.Node:=EnumeratorCurrentNode;
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// search expression type of 'enumerator current'
|
||||||
|
Params.Clear;
|
||||||
|
Params.Flags:=[fdfFunctionResult];
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator searching enumerator current result ...']);
|
||||||
|
{$ENDIF}
|
||||||
|
ResultExprType:=EnumeratorCurrentTool.ConvertNodeToExpressionType(
|
||||||
|
EnumeratorCurrentNode,Params);
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.FindOperatorEnumerator enumerator current result=',ExprTypeToString(ResultExprType)]);
|
||||||
|
{$ENDIF}
|
||||||
|
Result:=true;
|
||||||
|
finally
|
||||||
|
Params.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.CheckOperatorEnumerator(
|
||||||
|
Params: TFindDeclarationParams; const FoundContext: TFindContext
|
||||||
|
): TIdentifierFoundResult;
|
||||||
|
var
|
||||||
|
Node: TCodeTreeNode;
|
||||||
|
ExprType: TExpressionType;
|
||||||
|
Params2: TFindDeclarationParams;
|
||||||
|
begin
|
||||||
|
Result:=ifrProceedSearch;
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.CheckOperatorEnumerator ',FindContextToString(FoundContext)]);
|
||||||
|
{$ENDIF}
|
||||||
|
if not FoundContext.Tool.NodeIsOperator(FoundContext.Node) then exit;
|
||||||
|
FoundContext.Tool.BuildSubTreeForProcHead(FoundContext.Node);
|
||||||
|
Node:=FoundContext.Node.FirstChild;
|
||||||
|
if (Node=nil) or (Node.Desc<>ctnProcedureHead) then exit;
|
||||||
|
Node:=Node.FirstChild;
|
||||||
|
if (Node=nil) or (Node.Desc<>ctnParameterList) then exit;
|
||||||
|
Node:=Node.FirstChild;
|
||||||
|
if (Node=nil) then exit;
|
||||||
|
if Node.NextBrother<>nil then exit;
|
||||||
|
ExprType:=PExpressionType(Params.Data)^;
|
||||||
|
Params2:=TFindDeclarationParams.Create;
|
||||||
|
try
|
||||||
|
if IsCompatible(Node,ExprType,Params2)=tcIncompatible then exit;
|
||||||
|
finally
|
||||||
|
Params2.Free;
|
||||||
|
end;
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn(['TFindDeclarationTool.CheckOperatorEnumerator FOUND ',FoundContext.Tool.ExtractNode(FoundContext.Node,[])]);
|
||||||
|
{$ENDIF}
|
||||||
|
Result:=ifrSuccess;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.CheckModifierEnumeratorCurrent(
|
||||||
|
Params: TFindDeclarationParams; const FoundContext: TFindContext
|
||||||
|
): TIdentifierFoundResult;
|
||||||
|
begin
|
||||||
|
Result:=ifrProceedSearch;
|
||||||
|
//DebugLn(['TFindDeclarationTool.CheckModifierEnumeratorCurrent ',FindContextToString(FoundContext)]);
|
||||||
|
case FoundContext.Node.Desc of
|
||||||
|
ctnProperty:
|
||||||
|
begin
|
||||||
|
if FoundContext.Tool.PropertyHasSpecifier(FoundContext.Node,'Enumerator',false)
|
||||||
|
then begin
|
||||||
|
FoundContext.Tool.ReadNextAtom;
|
||||||
|
if FoundContext.Tool.UpAtomIs('CURRENT') then
|
||||||
|
Result:=ifrSuccess;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFindDeclarationTool.IsTermEdgedBracket(TermPos: TAtomPosition; out
|
function TFindDeclarationTool.IsTermEdgedBracket(TermPos: TAtomPosition; out
|
||||||
EdgedBracketsStartPos: integer): boolean;
|
EdgedBracketsStartPos: integer): boolean;
|
||||||
{ allowed:
|
{ allowed:
|
||||||
|
@ -1903,12 +1903,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
ReadNextAtom;
|
ReadNextAtom;
|
||||||
end;
|
end;
|
||||||
// read default
|
// read modifiers
|
||||||
while CurPos.Flag=cafSemicolon do begin
|
while CurPos.Flag=cafSemicolon do begin
|
||||||
ReadNextAtom;
|
ReadNextAtom;
|
||||||
if UpAtomIs('DEFAULT') or UpAtomIs('NODEFAULT') or UpAtomIs('DEPRECATED')
|
if UpAtomIs('DEFAULT') or UpAtomIs('NODEFAULT') or UpAtomIs('DEPRECATED')
|
||||||
then begin
|
then begin
|
||||||
if AtomIs(s) then exit(true);
|
if CompareIdentifierPtrs(@Src[CurPos.StartPos],Pointer(s))=0 then exit(true);
|
||||||
|
end else if UpAtomIs('ENUMERATOR') then begin
|
||||||
|
if CompareIdentifierPtrs(@Src[CurPos.StartPos],Pointer(s))=0 then exit(true);
|
||||||
|
ReadNextAtom;
|
||||||
|
if not AtomIsIdentifier(false) then exit;
|
||||||
end else
|
end else
|
||||||
exit;
|
exit;
|
||||||
ReadNextAtom;
|
ReadNextAtom;
|
||||||
|
Loading…
Reference in New Issue
Block a user