2
***************************************************************************
4
* This source is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This code is distributed in the hope that it will be useful, but *
10
* WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12
* General Public License for more details. *
14
* A copy of the GNU General Public License is available on the World *
15
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
16
* obtain it by writing to the Free Software Foundation, *
17
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************
21
Author: Mattias Gaertner
24
TIdentCompletionTool enhances the TFindDeclarationTool with the ability
25
to create lists of valid identifiers at a specific code position.
27
unit IdentCompletionTool;
35
// activate for debug:
42
{ $DEFINE ShowFoundIdents}
43
{ $DEFINE ShowFilteredIdents}
44
{ $DEFINE ShowHistory}
50
Classes, SysUtils, FileProcs, CodeTree, CodeAtom, CodeCache, CustomCodeTool,
51
CodeToolsStrConsts, KeywordFuncLists, BasicCodeTools, LinkScanner, AVL_Tree,
52
CodeToolMemManager, DefineTemplates, SourceChanger, FindDeclarationTool,
53
PascalReaderTool, PascalParserTool, CodeToolsStructs, ExprEval;
56
TIdentCompletionTool = class;
57
TIdentifierHistoryList = class;
59
//----------------------------------------------------------------------------
60
// gathered identifier list
62
TIdentifierCompatibility = (
68
TIdentifierCompatibilities = set of TIdentifierCompatibility;
70
TIdentListItemFlag = (
76
iliIsAbstractMethodValid,
77
iliParamTypeListValid,
78
iliParamNameListValid,
83
iliIsConstructorValid,
94
iliHintModifiersValid,
100
iliAtCursor // the item is the identifier at the completion
102
TIdentListItemFlags = set of TIdentListItemFlag;
104
{ TIdentifierListSearchItem }
106
TIdentifierListSearchItem = class
110
function CalcMemSize: PtrUInt;
113
{ TIdentifierListItem }
115
TIdentifierListItem = class
117
FParamTypeList: string;
118
FParamNameList: string;
119
FNode: TCodeTreeNode;
121
FToolNodesDeletedStep: integer;// only valid if iliNodeValid
122
FNodeStartPos: integer;
123
FNodeDesc: TCodeTreeNodeDesc;
125
function GetNode: TCodeTreeNode;
126
function GetParamTypeList: string;
127
function GetParamNameList: string;
128
procedure SetNode(const AValue: TCodeTreeNode);
129
procedure SetParamTypeList(const AValue: string);
130
procedure SetParamNameList(const AValue: string);
131
procedure SetResultType(const AValue: string);
133
Compatibility: TIdentifierCompatibility;
134
HistoryIndex: integer;
137
Tool: TFindDeclarationTool;
138
DefaultDesc: TCodeTreeNodeDesc;
139
Flags: TIdentListItemFlags;
140
BaseExprType: TExpressionType;
141
function AsString: string;
142
function GetDesc: TCodeTreeNodeDesc;
143
constructor Create(NewCompatibility: TIdentifierCompatibility;
144
NewHasChilds: boolean; NewHistoryIndex: integer;
145
NewIdentifier: PChar; NewLevel: integer;
146
NewNode: TCodeTreeNode; NewTool: TFindDeclarationTool;
147
NewDefaultDesc: TCodeTreeNodeDesc);
148
function IsProcNodeWithParams: boolean;
149
function IsPropertyWithParams: boolean;
150
function IsPropertyReadOnly: boolean;
151
function GetHintModifiers: TPascalHintModifiers;
152
function CheckHasChilds: boolean;
153
function CanBeAssigned: boolean;
154
procedure UpdateBaseContext;
155
function HasChilds: boolean;
156
function HasIndex: boolean;
157
function IsFunction: boolean;
158
function IsContructor: boolean;
159
function IsDestructor: boolean;
160
function IsAbstractMethod: boolean;
161
function TryIsAbstractMethod: boolean;
163
procedure UnbindNode;
164
procedure StoreNodeHash;
165
function RestoreNode: boolean;
166
function GetNodeHash(ANode: TCodeTreeNode): string;
167
function CompareParamList(CompareItem: TIdentifierListItem): integer;
168
function CompareParamList(CompareItem: TIdentifierListSearchItem): integer;
169
function CalcMemSize: PtrUInt;
171
property ParamTypeList: string read GetParamTypeList write SetParamTypeList;
172
property ParamNameList: string read GetParamNameList write SetParamNameList;
173
property ResultType: string read FResultType write SetResultType;
174
property Node: TCodeTreeNode read GetNode write SetNode;
177
TIdentifierListFlag = (
178
ilfFilteredListNeedsUpdate,
179
ilfUsedToolsNeedsUpdate
181
TIdentifierListFlags = set of TIdentifierListFlag;
183
TIdentifierListContextFlag = (
184
ilcfStartInStatement, // context starts in statements. e.g. between begin..end
185
ilcfStartOfStatement, // atom is start of statement. e.g. 'A|:=' or 'A|;', does not check if A can be assigned
186
ilcfStartOfOperand, // atom is start of an operand. e.g. 'A|.B'
187
ilcfStartIsSubIdent, // atom in front is point
188
ilcfNeedsEndSemicolon, // after context a semicolon is needed. e.g. 'A| end'
189
ilcfNoEndSemicolon, // no semicolon after. E.g. 'A| else'
190
ilcfNeedsEndComma, // after context a comma is needed. e.g. 'uses sysutil| classes'
191
ilcfNeedsDo, // after context a 'do' is needed. e.g. 'with Form1| do'
192
ilcfIsExpression, // is expression part of statement. e.g. 'if expr'
193
ilcfCanProcDeclaration,// context allows to declare a procedure/method
194
ilcfEndOfLine // atom at end of line
196
TIdentifierListContextFlags = set of TIdentifierListContextFlag;
198
TIdentifierList = class
200
FContext: TFindContext;
201
FNewMemberVisibility: TCodeTreeNodeDesc;
202
FContextFlags: TIdentifierListContextFlags;
203
FStartAtom: TAtomPosition;
204
FStartAtomBehind: TAtomPosition;
205
FStartAtomInFront: TAtomPosition;
206
FStartBracketLvl: integer;
207
FStartContextPos: TCodeXYPosition;
208
FCreatedIdentifiers: TFPList; // list of PChar
209
FFilteredList: TFPList; // list of TIdentifierListItem
210
FFlags: TIdentifierListFlags;
211
FHistory: TIdentifierHistoryList;
212
FItems: TAVLTree; // tree of TIdentifierListItem (completely sorted)
213
FIdentView: TAVLTree; // tree of TIdentHistListItem sorted for identifiers
214
FUsedTools: TAVLTree; // tree of TFindDeclarationTool
215
FIdentSearchItem: TIdentifierListSearchItem;
217
FStartContext: TFindContext;
218
procedure SetHistory(const AValue: TIdentifierHistoryList);
219
procedure UpdateFilteredList;
220
function GetFilteredItems(Index: integer): TIdentifierListItem;
221
procedure SetPrefix(const AValue: string);
224
destructor Destroy; override;
226
procedure Add(NewItem: TIdentifierListItem);
227
function Count: integer;
228
function GetFilteredCount: integer;
229
function HasIdentifier(Identifier: PChar; const ParamList: string): boolean;
230
function FindIdentifier(Identifier: PChar; const ParamList: string): TIdentifierListItem;
231
function FindCreatedIdentifier(const Ident: string): integer;
232
function CreateIdentifier(const Ident: string): PChar;
233
function StartUpAtomInFrontIs(const s: string): boolean;
234
function StartUpAtomBehindIs(const s: string): boolean;
235
function CompletePrefix(const OldPrefix: string): string;
236
function CalcMemSize: PtrUInt;
238
property Context: TFindContext read FContext write FContext;
239
property ContextFlags: TIdentifierListContextFlags
240
read FContextFlags write FContextFlags;
241
property NewMemberVisibility: TCodeTreeNodeDesc // identifier is a class member, e.g. a variable or a procedure name
242
read FNewMemberVisibility write FNewMemberVisibility;
243
property FilteredItems[Index: integer]: TIdentifierListItem
244
read GetFilteredItems;
245
property History: TIdentifierHistoryList read FHistory write SetHistory;
246
property Prefix: string read FPrefix write SetPrefix;
247
property StartAtom: TAtomPosition read FStartAtom write FStartAtom;
248
property StartAtomInFront: TAtomPosition
249
read FStartAtomInFront write FStartAtomInFront; // in front of variable, not only of identifier
250
property StartAtomBehind: TAtomPosition
251
read FStartAtomBehind write FStartAtomBehind; // directly behind
252
property StartBracketLvl: integer
253
read FStartBracketLvl write FStartBracketLvl;
254
property StartContext: TFindContext read FStartContext write FStartContext;
255
property StartContextPos: TCodeXYPosition
256
read FStartContextPos write FStartContextPos;
259
//----------------------------------------------------------------------------
262
{ TIdentHistListItem }
264
TIdentHistListItem = class
267
NodeDesc: TCodeTreeNodeDesc;
269
HistoryIndex: integer;
270
function CalcMemSize: PtrUInt;
273
{ TIdentifierHistoryList }
275
TIdentifierHistoryList = class
278
FItems: TAVLTree; // tree of TIdentHistListItem
279
procedure SetCapacity(const AValue: integer);
280
function FindItem(NewItem: TIdentifierListItem): TAVLTreeNode;
283
destructor Destroy; override;
285
procedure Add(NewItem: TIdentifierListItem);
286
function GetHistoryIndex(AnItem: TIdentifierListItem): integer;
287
function Count: integer;
288
function CalcMemSize: PtrUInt;
290
property Capacity: integer read FCapacity write SetCapacity;
294
//----------------------------------------------------------------------------
296
{ TCodeContextInfoItem }
298
TCodeContextInfoItem = class
300
Expr: TExpressionType;
301
// compiler predefined proc
305
destructor Destroy; override;
310
TCodeContextInfo = class
313
FItems: TFPList; // list of TCodeContextInfoItem
314
FParameterIndex: integer;
316
FProcNameAtom: TAtomPosition;
318
FTool: TFindDeclarationTool;
319
function GetItems(Index: integer): TCodeContextInfoItem;
322
destructor Destroy; override;
323
function Count: integer;
324
property Items[Index: integer]: TCodeContextInfoItem read GetItems; default;
325
function Add(const Context: TExpressionType): integer;
326
function AddCompilerProc: integer;
328
property Tool: TFindDeclarationTool read FTool write FTool;
329
property ParameterIndex: integer read FParameterIndex write FParameterIndex;// 1 based
330
property ProcName: string read FProcName write FProcName;
331
property ProcNameAtom: TAtomPosition read FProcNameAtom write FProcNameAtom;
332
property StartPos: integer read FStartPos write FStartPos;// context is valid from StartPos to EndPos
333
property EndPos: integer read FEndPos write FEndPos;
335
function CalcMemSize: PtrUInt;
338
//----------------------------------------------------------------------------
339
// TIdentCompletionTool
341
TIdentCompletionTool = class(TFindDeclarationTool)
343
FLastGatheredIdentParent: TCodeTreeNode;
344
FLastGatheredIdentLevel: integer;
345
FICTClassAndAncestors: TFPList;// list of PCodeXYPosition
346
FIDCTFoundPublicProperties: TAVLTree;// tree of PChar (pointing to the
347
// property names in source)
348
FIDTFoundMethods: TAVLTree;// tree of TCodeTreeNodeExtension Txt=clean text
349
FIDTTreeOfUnitFiles: TAVLTree;// tree of TUnitFileInfo
350
procedure AddToTreeOfUnitFileInfo(const AFilename: string);
352
CurrentIdentifierList: TIdentifierList;
353
CurrentIdentifierContexts: TCodeContextInfo;
354
function CollectAllIdentifiers(Params: TFindDeclarationParams;
355
const FoundContext: TFindContext): TIdentifierFoundResult;
356
procedure GatherPredefinedIdentifiers(CleanPos: integer;
357
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
358
procedure GatherUsefulIdentifiers(CleanPos: integer;
359
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
360
procedure GatherUnitnames;
361
procedure GatherSourceNames(const Context: TFindContext);
362
procedure GatherContextKeywords(const Context: TFindContext;
363
CleanPos: integer; BeautifyCodeOptions: TBeautifyCodeOptions);
364
procedure InitCollectIdentifiers(const CursorPos: TCodeXYPosition;
365
var IdentifierList: TIdentifierList);
366
procedure ParseSourceTillCollectionStart(const CursorPos: TCodeXYPosition;
367
out CleanCursorPos: integer; out CursorNode: TCodeTreeNode;
368
out IdentStartPos, IdentEndPos: integer);
369
function FindIdentifierStartPos(const CursorPos: TCodeXYPosition
371
procedure FindCollectionContext(Params: TFindDeclarationParams;
372
IdentStartPos: integer; CursorNode: TCodeTreeNode;
373
out GatherContext: TFindContext; out ContextExprStartPos: LongInt;
374
out StartInSubContext: Boolean);
375
function CollectAllContexts(Params: TFindDeclarationParams;
376
const FoundContext: TFindContext): TIdentifierFoundResult;
377
procedure AddCollectionContext(Tool: TFindDeclarationTool;
378
Node: TCodeTreeNode);
379
procedure InitFoundMethods;
380
procedure ClearFoundMethods;
381
function CollectMethods(Params: TFindDeclarationParams;
382
const FoundContext: TFindContext): TIdentifierFoundResult;
383
function IsInCompilerDirective(CursorPos: TCodeXYPosition): boolean;
385
function GatherAvailableUnitNames(const CursorPos: TCodeXYPosition;
386
var IdentifierList: TIdentifierList): Boolean;
387
function GatherIdentifiers(const CursorPos: TCodeXYPosition;
388
var IdentifierList: TIdentifierList;
389
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
390
function FindCodeContext(const CursorPos: TCodeXYPosition;
391
out CodeContexts: TCodeContextInfo): boolean;
392
function FindAbstractMethods(const CursorPos: TCodeXYPosition;
393
out ListOfPCodeXYPosition: TFPList;
394
SkipAbstractsInStartClass: boolean = false): boolean;
395
function GetValuesOfCaseVariable(const CursorPos: TCodeXYPosition;
396
List: TStrings): boolean;
398
procedure CalcMemSize(Stats: TCTMemStats); override;
403
function CompareIdentListItems(Data1, Data2: Pointer): integer;
405
Item1: TIdentifierListItem;
406
Item2: TIdentifierListItem;
408
Item1:=TIdentifierListItem(Data1);
409
Item2:=TIdentifierListItem(Data2);
411
// first sort for Compatibility (lower is better)
412
if ord(Item1.Compatibility)<ord(Item2.Compatibility) then begin
415
end else if ord(Item1.Compatibility)>ord(Item2.Compatibility) then begin
420
// then sort for History (lower is better)
421
if Item1.HistoryIndex<Item2.HistoryIndex then begin
424
end else if Item1.HistoryIndex>Item2.HistoryIndex then begin
429
// then sort for Level (lower is better)
430
if Item1.Level<Item2.Level then begin
433
end else if Item1.Level>Item2.Level then begin
438
// then sort alpabetically (lower is better)
439
Result:=CompareIdentifierPtrs(Pointer(Item2.Identifier),Pointer(Item1.Identifier));
440
if Result<>0 then exit;
442
// then sort for ParamList (lower is better)
443
Result:=Item2.CompareParamList(Item1);
446
function CompareIdentListItemsForIdents(Data1, Data2: Pointer): integer;
448
Item1: TIdentifierListItem;
449
Item2: TIdentifierListItem;
451
Item1:=TIdentifierListItem(Data1);
452
Item2:=TIdentifierListItem(Data2);
454
// sort alpabetically (lower is better)
455
Result:=CompareIdentifierPtrs(Pointer(Item2.Identifier),Pointer(Item1.Identifier));
456
if Result<>0 then exit;
458
// then sort for ParamList (lower is better)
459
Result:=Item2.CompareParamList(Item1);
462
function CompareIdentListSearchWithItems(SearchItem, Item: Pointer): integer;
464
TheSearchItem: TIdentifierListSearchItem;
465
TheItem: TIdentifierListItem;
467
TheSearchItem:=TIdentifierListSearchItem(SearchItem);
468
TheItem:=TIdentifierListItem(Item);
470
// sort alpabetically (lower is better)
471
Result:=CompareIdentifierPtrs(Pointer(TheItem.Identifier),TheSearchItem.Identifier);
472
if Result<>0 then exit;
474
// then sort for ParamList (lower is better)
475
Result:=TheItem.CompareParamList(TheSearchItem);
478
function CompareIdentHistListItem(Data1, Data2: Pointer): integer;
480
Item1: TIdentHistListItem;
481
Item2: TIdentHistListItem;
483
Item1:=TIdentHistListItem(Data1);
484
Item2:=TIdentHistListItem(Data2);
486
Result:=CompareIdentifiers(PChar(Pointer(Item2.Identifier)),
487
PChar(Pointer(Item1.Identifier)));
488
if Result<>0 then exit;
490
//debugln('CompareIdentHistListItem ',Item2.Identifier,'=',Item1.Identifier);
491
Result:=CompareIdentifiers(PChar(Pointer(Item2.ParamList)),
492
PChar(Pointer(Item1.ParamList)));
495
function CompareIdentItemWithHistListItem(Data1, Data2: Pointer): integer;
497
IdentItem: TIdentifierListItem;
498
HistItem: TIdentHistListItem;
500
IdentItem:=TIdentifierListItem(Data1);
501
HistItem:=TIdentHistListItem(Data2);
503
Result:=CompareIdentifierPtrs(Pointer(HistItem.Identifier),
504
Pointer(IdentItem.Identifier));
505
if Result<>0 then exit;
507
//debugln('CompareIdentItemWithHistListItem ',HistItem.Identifier,'=',GetIdentifier(IdentItem.Identifier));
508
Result:=SysUtils.CompareText(HistItem.ParamList,IdentItem.ParamTypeList);
513
procedure TIdentifierList.SetPrefix(const AValue: string);
515
if FPrefix=AValue then exit;
517
Include(FFlags,ilfFilteredListNeedsUpdate);
520
procedure TIdentifierList.UpdateFilteredList;
522
AnAVLNode: TAVLTreeNode;
523
CurItem: TIdentifierListItem;
525
if not (ilfFilteredListNeedsUpdate in FFlags) then exit;
526
if FFilteredList=nil then FFilteredList:=TFPList.Create;
527
FFilteredList.Count:=0;
528
FFilteredList.Capacity:=FItems.Count;
530
DebugLn(['TIdentifierList.UpdateFilteredList Prefix="',Prefix,'"']);
532
AnAVLNode:=FItems.FindLowest;
533
while AnAVLNode<>nil do begin
534
CurItem:=TIdentifierListItem(AnAVLNode.Data);
535
if (CurItem.Identifier<>'')
536
and ComparePrefixIdent(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier)))
538
{$IFDEF ShowFilteredIdents}
539
DebugLn(['::: FILTERED ITEM ',FFilteredList.Count,' ',CurItem.Identifier]);
541
if (length(Prefix)=length(CurItem.Identifier))
542
and (not (iliAtCursor in CurItem.Flags)) then
543
// put exact matches at the beginning
544
FFilteredList.Insert(0,CurItem)
546
FFilteredList.Add(CurItem);
548
AnAVLNode:=FItems.FindSuccessor(AnAVLNode);
551
DebugLn(['TIdentifierList.UpdateFilteredList ',dbgs(FFilteredList.Count),' of ',dbgs(FItems.Count)]);
553
Exclude(FFlags,ilfFilteredListNeedsUpdate);
556
procedure TIdentifierList.SetHistory(const AValue: TIdentifierHistoryList);
558
if FHistory=AValue then exit;
562
function TIdentifierList.GetFilteredItems(Index: integer): TIdentifierListItem;
565
if (Index<0) or (Index>=FFilteredList.Count) then
568
Result:=TIdentifierListItem(FFilteredList[Index]);
571
constructor TIdentifierList.Create;
573
FFlags:=[ilfFilteredListNeedsUpdate];
574
FItems:=TAVLTree.Create(@CompareIdentListItems);
575
FIdentView:=TAVLTree.Create(@CompareIdentListItemsForIdents);
576
FIdentSearchItem:=TIdentifierListSearchItem.Create;
577
FCreatedIdentifiers:=TFPList.Create;
580
destructor TIdentifierList.Destroy;
583
FreeAndNil(FUsedTools);
585
FreeAndNil(FIdentView);
586
FreeAndNil(FFilteredList);
587
FreeAndNil(FIdentSearchItem);
588
FreeAndNil(FCreatedIdentifiers);
592
procedure TIdentifierList.Clear;
598
fContext:=CleanFindContext;
599
FNewMemberVisibility:=ctnNone;
601
fStartContext:=CleanFindContext;
602
fStartContextPos.Code:=nil;
603
fStartContextPos.X:=1;
604
fStartContextPos.Y:=1;
605
for i:=0 to FCreatedIdentifiers.Count-1 do begin
606
p:=FCreatedIdentifiers[i];
609
FCreatedIdentifiers.Clear;
612
if FUsedTools<>nil then
614
FFlags:=FFlags+[ilfFilteredListNeedsUpdate,ilfUsedToolsNeedsUpdate];
617
procedure TIdentifierList.Add(NewItem: TIdentifierListItem);
619
AnAVLNode: TAVLTreeNode;
621
AnAVLNode:=FIdentView.FindKey(NewItem,@CompareIdentListItemsForIdents);
622
if AnAVLNode=nil then begin
624
NewItem.HistoryIndex:=History.GetHistoryIndex(NewItem);
626
FIdentView.Add(NewItem);
627
FFlags:=FFlags+[ilfFilteredListNeedsUpdate,ilfUsedToolsNeedsUpdate];
629
// redefined identifier -> ignore
630
//DebugLn('TIdentifierList.Add redefined: ',NewItem.AsString);
635
function TIdentifierList.Count: integer;
637
Result:=FItems.Count;
640
function TIdentifierList.GetFilteredCount: integer;
643
Result:=FFilteredList.Count;
646
function TIdentifierList.HasIdentifier(Identifier: PChar;
647
const ParamList: string): boolean;
649
FIdentSearchItem.Identifier:=Identifier;
650
FIdentSearchItem.ParamList:=ParamList;
651
Result:=FIdentView.FindKey(FIdentSearchItem,
652
@CompareIdentListSearchWithItems)<>nil;
655
function TIdentifierList.FindIdentifier(Identifier: PChar;
656
const ParamList: string): TIdentifierListItem;
658
AVLNode: TAVLTreeNode;
660
FIdentSearchItem.Identifier:=Identifier;
661
FIdentSearchItem.ParamList:=ParamList;
662
AVLNode:=FIdentView.FindKey(FIdentSearchItem,@CompareIdentListSearchWithItems);
664
Result:=TIdentifierListItem(AVLNode.Data)
669
function TIdentifierList.FindCreatedIdentifier(const Ident: string): integer;
671
if Ident<>'' then begin
672
Result:=FCreatedIdentifiers.Count-1;
674
and (CompareIdentifiers(PChar(Pointer(Ident)),
675
PChar(Pointer(FCreatedIdentifiers[Result])))<>0)
683
function TIdentifierList.CreateIdentifier(const Ident: string): PChar;
687
if Ident<>'' then begin
688
i:=FindCreatedIdentifier(Ident);
690
Result:=PChar(Pointer(FCreatedIdentifiers[i]))
692
GetMem(Result,length(Ident)+1);
693
Move(Ident[1],Result^,length(Ident)+1);
694
FCreatedIdentifiers.Add(Result);
700
function TIdentifierList.StartUpAtomInFrontIs(const s: string): boolean;
702
Result:=StartContext.Tool.FreeUpAtomIs(StartAtomInFront,s);
705
function TIdentifierList.StartUpAtomBehindIs(const s: string): boolean;
707
Result:=StartContext.Tool.FreeUpAtomIs(StartAtomBehind,s);
710
function TIdentifierList.CompletePrefix(const OldPrefix: string): string;
711
// search all identifiers beginning with Prefix
712
// and return the biggest prefix of all of them
714
AnAVLNode: TAVLTreeNode;
715
CurItem: TIdentifierListItem;
722
AnAVLNode:=FItems.FindLowest;
723
while AnAVLNode<>nil do begin
724
CurItem:=TIdentifierListItem(AnAVLNode.Data);
725
if (CurItem.Identifier<>'')
726
and ComparePrefixIdent(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier)))
727
and (not (iliAtCursor in CurItem.Flags))
729
if not FoundFirst then begin
730
Result:=CurItem.Identifier;
733
SamePos:=length(Prefix)+1;
735
if l>length(CurItem.Identifier) then
736
l:=length(CurItem.Identifier);
738
and (UpChars[CurItem.Identifier[SamePos]]=UpChars[Result[SamePos]])
741
if SamePos<=length(Result) then begin
742
Result:=copy(Result,1,SamePos-1);
743
if length(Result)=length(Prefix) then exit;
747
AnAVLNode:=FItems.FindSuccessor(AnAVLNode);
751
function TIdentifierList.CalcMemSize: PtrUInt;
755
li: TIdentifierListItem;
756
hli: TIdentHistListItem;
758
Result:=PtrUInt(InstanceSize)
759
+MemSizeString(FPrefix);
760
if FCreatedIdentifiers<>nil then begin
761
inc(Result,MemSizeFPList(FCreatedIdentifiers));
762
for i:=0 to FCreatedIdentifiers.Count-1 do
763
inc(Result,GetIdentLen(PChar(FCreatedIdentifiers[i])));
765
if FFilteredList<>nil then begin
766
inc(Result,MemSizeFPList(FFilteredList));
767
for i:=0 to FFilteredList.Count-1 do
768
inc(Result,TIdentifierListItem(FFilteredList[i]).CalcMemSize);
770
if FHistory<>nil then begin
771
inc(Result,FHistory.CalcMemSize);
773
if FItems<>nil then begin
774
inc(Result,FItems.Count*SizeOf(TAVLTreeNode));
775
Node:=FItems.FindLowest;
776
while Node<>nil do begin
777
li:=TIdentifierListItem(Node.Data);
778
inc(Result,li.CalcMemSize);
779
Node:=FItems.FindSuccessor(Node);
782
if FIdentView<>nil then begin
783
inc(Result,FIdentView.Count*SizeOf(TAVLTreeNode));
784
Node:=FIdentView.FindLowest;
785
while Node<>nil do begin
786
hli:=TIdentHistListItem(Node.Data);
787
inc(Result,hli.CalcMemSize);
788
Node:=FIdentView.FindSuccessor(Node);
791
if FIdentSearchItem<>nil then
792
inc(Result,FIdentSearchItem.CalcMemSize);
795
{ TIdentCompletionTool }
797
procedure TIdentCompletionTool.AddToTreeOfUnitFileInfo(const AFilename: string);
799
AddToTreeOfUnitFiles(FIDTTreeOfUnitFiles,AFilename,false);
802
function TIdentCompletionTool.CollectAllIdentifiers(
803
Params: TFindDeclarationParams; const FoundContext: TFindContext
804
): TIdentifierFoundResult;
807
CurContextParent: TCodeTreeNode;
809
function ProtectedNodeIsInAllowedClass: boolean;
811
CurClassNode: TCodeTreeNode;
812
FoundClassContext: TFindContext;
815
if FICTClassAndAncestors<>nil then begin
816
// start of the identifier completion is in a method or class
817
// => all protected ancestor classes are allowed as well.
818
CurClassNode:=FoundContext.Node;
819
while (CurClassNode<>nil)
820
and (not (CurClassNode.Desc in AllClasses)) do
821
CurClassNode:=CurClassNode.Parent;
822
if CurClassNode=nil then exit;
823
FoundClassContext:=CreateFindContext(Params.NewCodeTool,CurClassNode);
824
if IndexOfFindContext(FICTClassAndAncestors,@FoundClassContext)>=0 then begin
825
// this class node is the class or one of the ancestors of the class
826
// of the start context of the identifier completion
830
//DebugLn(['ProtectedNodeIsInAllowedClass hidden: ',FindContextToString(FoundContext)]);
833
function PropertyIsOverridenPublicPublish: boolean;
835
// protected properties can be made public in child classes.
836
//debugln('PropertyIsOverridenPublicPublish Identifier=',GetIdentifier(Ident),' Find=',dbgs((FIDCTFoundPublicProperties<>nil) and (FIDCTFoundPublicProperties.Find(Ident)<>nil)));
837
if FIDCTFoundPublicProperties<>nil then begin
838
if FIDCTFoundPublicProperties.Find(Ident)<>nil then begin
839
// there is a public/published property with the same name
846
procedure SavePublicPublishedProperty;
848
if FIDCTFoundPublicProperties=nil then begin
850
FIDCTFoundPublicProperties:=
851
TAVLTree.Create(TListSortCompare(@CompareIdentifiers))
852
end else if FIDCTFoundPublicProperties.Find(Ident)<>nil then begin
853
// identifier is already public
856
FIDCTFoundPublicProperties.Add(Ident);
857
//debugln('SavePublicPublishedProperty Identifier=',GetIdentifier(Ident),' Find=',dbgs(FIDCTFoundPublicProperties.Find(Ident)<>nil));
861
NewItem: TIdentifierListItem;
863
ProtectedForeignClass: Boolean;
865
NamePos: TAtomPosition;
867
// proceed searching ...
868
Result:=ifrProceedSearch;
870
{$IFDEF ShowFoundIdents}
871
if FoundContext.Tool=Self then
872
DebugLn('::: COLLECT IDENT ',FoundContext.Node.DescAsString,
873
' "',StringToPascalConst(copy(FoundContext.Tool.Src,FoundContext.Node.StartPos,50)),'"'
874
,' '+dbgs(fdfIgnoreUsedUnits in Params.Flags));
877
CurContextParent:=FoundContext.Node.GetFindContextParent;
878
if FLastGatheredIdentParent<>CurContextParent then begin
880
FLastGatheredIdentParent:=CurContextParent;
881
inc(FLastGatheredIdentLevel);
884
Lvl:=FLastGatheredIdentLevel;
886
ProtectedForeignClass:=false;
887
if FoundContext.Tool=Self then begin
888
// identifier is in the same unit
889
//DebugLn('::: COLLECT IDENT in SELF ',FoundContext.Node.DescAsString,
890
// ' "',dbgstr(FoundContext.Tool.Src,FoundContext.Node.StartPos,50),'"'
891
// ,' fdfIgnoreUsedUnits='+dbgs(fdfIgnoreUsedUnits in Params.Flags));
892
if (FoundContext.Node=CurrentIdentifierList.StartContext.Node)
893
or (FoundContext.Node=CurrentIdentifierList.Context.Node)
894
or (FoundContext.Node.StartPos=CurrentIdentifierList.StartAtom.StartPos)
896
// found identifier is in cursor node
901
// identifier is in another unit
902
Node:=FoundContext.Node.Parent;
903
if (Node<>nil) and (Node.Desc in AllClassSubSections) then
905
if (Node<>nil) and (Node.Desc in AllClassBaseSections) then begin
906
//debugln(['TIdentCompletionTool.CollectAllIdentifiers Node=',Node.DescAsString,' Context=',CurrentIdentifierList.Context.Node.DescAsString,' CtxVis=',NodeDescToStr(CurrentIdentifierList.NewMemberVisibility)]);
907
if (CurrentIdentifierList.NewMemberVisibility<>ctnNone)
908
and (CurrentIdentifierList.NewMemberVisibility<Node.Desc)
909
and (CurrentIdentifierList.Context.Node.Desc
910
in ([ctnProcedure,ctnProcedureHead,ctnProperty]+AllClassSections))
912
// the user wants to override a method or property
913
// => ignore all with a higher visibility, because fpc does not allow
914
// to downgrade the visibility and will give a hint when trying
915
//debugln(['TIdentCompletionTool.CollectAllIdentifiers skipping member, because it would downgrade: ',dbgstr(FoundContext.Tool.ExtractNode(FoundContext.Node,[]),1,30)]);
921
// skip private definitions in other units
926
// protected definitions are only accessible from descendants
927
// or if visibility was raised (e.g. property)
928
if ProtectedNodeIsInAllowedClass then begin
929
// protected node in an ancestor => allowed
930
//debugln('TIdentCompletionTool.CollectAllIdentifiers ALLOWED Protected in ANCESTOR '+StringToPascalConst(copy(FoundContext.Tool.Src,FoundContext.Node.StartPos,50)));
931
end else if (FoundContext.Node.Desc=ctnProperty) then begin
932
// protected property: maybe the visibility was raised => continue
933
ProtectedForeignClass:=true;
934
//debugln('TIdentCompletionTool.CollectAllIdentifiers MAYBE Protected made Public '+StringToPascalConst(copy(FoundContext.Tool.Src,FoundContext.Node.StartPos,50)));
936
// otherwise: treat as private
937
//debugln('TIdentCompletionTool.CollectAllIdentifiers FORBIDDEN Protected '+StringToPascalConst(copy(FoundContext.Tool.Src,FoundContext.Node.StartPos,50)));
946
case FoundContext.Node.Desc of
948
ctnTypeDefinition,ctnGenericType:
950
Node:=FoundContext.Node.FirstChild;
951
if FoundContext.Node.Desc=ctnTypeDefinition then
952
Ident:=@FoundContext.Tool.Src[FoundContext.Node.StartPos]
955
if Node=nil then exit;
956
Ident:=@FoundContext.Tool.Src[Node.StartPos];
958
if Node=nil then begin
959
// type without definition
962
and (Node.Desc in AllClasses)
963
and ((ctnsForwardDeclaration and Node.SubDesc)>0)
965
// forward definition of a class
966
if CurrentIdentifierList.FindIdentifier(Ident,'')<>nil then begin
967
// the real class is already in the list => skip forward
973
ctnVarDefinition,ctnConstDefinition,ctnEnumIdentifier:
974
Ident:=@FoundContext.Tool.Src[FoundContext.Node.StartPos];
976
ctnProcedure,ctnProcedureHead:
977
Ident:=FoundContext.Tool.GetProcNameIdentifier(FoundContext.Node);
981
Ident:=FoundContext.Tool.GetPropertyNameIdentifier(FoundContext.Node);
982
if FoundContext.Tool.PropNodeIsTypeLess(FoundContext.Node) then begin
983
if FoundContext.Node.Parent.Desc in [ctnClassPublic,ctnClassPublished]
985
SavePublicPublishedProperty;
986
// do not show properties without types (e.g. property Color;)
987
// only show the real definition, which will follow in the ancestor
990
if (FoundContext.Node.Parent.Desc=ctnClassPrivate)
991
and (FoundContext.Tool<>Self)
992
and (not PropertyIsOverridenPublicPublish) then begin
993
// a private property in another unit, that was not
994
// made public/publish later
998
if (FoundContext.Node.Parent.Desc=ctnClassProtected)
999
and ProtectedForeignClass
1000
and (not PropertyIsOverridenPublicPublish) then begin
1001
// a protected property in another unit, that was not
1002
// made public/publish later
1009
Ident:=@FoundContext.Tool.Src[Params.NewCleanPos];
1012
if (FoundContext.Tool=Self) then begin
1013
Ident:=@Src[FoundContext.Node.StartPos];
1016
ctnUnit,ctnProgram,ctnLibrary,ctnPackage:
1017
if (FoundContext.Tool=Self)
1018
and GetSourceNamePos(NamePos) then
1019
Ident:=@Src[NamePos.StartPos];
1022
if Ident=nil then exit;
1024
NewItem:=TIdentifierListItem.Create(
1033
if (FoundContext.Node=CurrentIdentifierList.StartContext.Node) then begin
1034
// found identifier is in cursor node
1035
Include(NewItem.Flags,iliAtCursor);
1038
{$IFDEF ShowFoundIdents}
1039
if FoundContext.Tool=Self then
1040
DebugLn(' IDENT COLLECTED: ',NewItem.AsString);
1043
CurrentIdentifierList.Add(NewItem);
1046
procedure TIdentCompletionTool.GatherPredefinedIdentifiers(CleanPos: integer;
1047
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
1048
// Add predefined identifiers
1050
CompilerFuncHistoryIndex = 10;
1051
CompilerFuncLevel = 10;
1053
function StatementLevel: integer;
1055
ANode: TCodeTreeNode;
1058
ANode:=Context.Node;
1059
while (ANode<>nil) and (not (ANode.Desc in [ctnBeginBlock,ctnAsmBlock])) do
1061
ANode:=ANode.Parent;
1064
if ANode=nil then Result:=0;
1067
procedure AddCompilerProcedure(const AProcName, AParameterList: PChar);
1069
NewItem: TIdentifierListItem;
1071
//DebugLn(['AddCompilerProcedure ',AProcName,' ',ilcfStartOfStatement in CurrentIdentifierList.ContextFlags]);
1072
if not (ilcfStartOfStatement in CurrentIdentifierList.ContextFlags) then exit;
1073
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
1075
NewItem:=TIdentifierListItem.Create(
1078
CompilerFuncHistoryIndex,
1084
NewItem.ParamTypeList:=AParameterList;
1085
NewItem.ParamNameList:=AParameterList;
1086
NewItem.Flags:=NewItem.Flags+[iliParamTypeListValid,iliParamNameListValid];
1087
CurrentIdentifierList.Add(NewItem);
1090
procedure AddCompilerFunction(const AProcName, AParameterList,
1091
AResultType: PChar);
1093
NewItem: TIdentifierListItem;
1095
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
1097
NewItem:=TIdentifierListItem.Create(
1100
CompilerFuncHistoryIndex,
1106
NewItem.ParamTypeList:=AParameterList;
1107
NewItem.ParamNameList:=AParameterList;
1108
NewItem.ResultType:=AResultType;
1109
NewItem.Flags:=NewItem.Flags+[iliParamTypeListValid,iliParamNameListValid,
1110
iliIsFunction,iliIsFunctionValid,iliResultTypeValid];
1111
CurrentIdentifierList.Add(NewItem);
1114
procedure AddBaseType(const BaseName: PChar);
1116
NewItem: TIdentifierListItem;
1118
NewItem:=TIdentifierListItem.Create(
1121
CompilerFuncHistoryIndex,
1127
CurrentIdentifierList.Add(NewItem);
1130
procedure AddBaseConstant(const BaseName: PChar);
1132
NewItem: TIdentifierListItem;
1134
NewItem:=TIdentifierListItem.Create(
1137
CompilerFuncHistoryIndex,
1143
CurrentIdentifierList.Add(NewItem);
1146
procedure AddSystemUnit(const AnUnitName: PChar);
1148
NewItem: TIdentifierListItem;
1150
NewItem:=TIdentifierListItem.Create(
1153
CompilerFuncHistoryIndex,
1159
CurrentIdentifierList.Add(NewItem);
1163
NewItem: TIdentifierListItem;
1164
ProcNode: TCodeTreeNode;
1165
HidddnUnits: String;
1168
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
1170
if Context.Node.Desc in AllPascalStatements then begin
1171
// see fpc/compiler/psystem.pp
1172
AddCompilerProcedure('Assert','Condition:Boolean;const Message:String');
1173
AddCompilerFunction('Assigned','P:Pointer','Boolean');
1174
AddCompilerFunction('Addr','var X','Pointer');
1175
AddCompilerFunction('BitSizeOf','Identifier','Integer');
1176
AddCompilerProcedure('Break','');
1177
AddCompilerFunction('Concat','S1:String;S2:String[...;Sn:String]', 'String');
1178
AddCompilerProcedure('Continue','');
1179
AddCompilerFunction('Copy','const S:String;FromPosition,Count:Integer', 'String');
1180
AddCompilerProcedure('Dec','var X:Ordinal;N:Integer=1');
1181
AddCompilerProcedure('Dispose','var X:Pointer');
1182
AddCompilerProcedure('Exclude','var S:Set;X:Ordinal');
1183
AddCompilerProcedure('Exit','');
1184
AddCompilerProcedure('Finalize','var X');
1185
AddCompilerFunction('get_frame','','Pointer');
1186
AddCompilerFunction('High','Arg:TypeOrVariable','Ordinal');
1187
AddCompilerProcedure('Inc','var X:Ordinal;N:Integer=1');
1188
AddCompilerProcedure('Include','var S:Set;X:Ordinal');
1189
AddCompilerProcedure('Initialize','var X');
1190
AddCompilerFunction('Length','S:String','Ordinal');
1191
AddCompilerFunction('Length','A:Array','Ordinal');
1192
AddCompilerFunction('Low','Arg:TypeOrVariable','Ordinal');
1193
AddCompilerProcedure('New','var X:Pointer');
1194
AddCompilerFunction('ObjCSelector','String','SEL');
1195
AddCompilerFunction('Ofs','var X','LongInt');
1196
AddCompilerFunction('Ord','X:Ordinal', 'Integer');
1197
AddCompilerProcedure('Pack','A:Array;N:Integer;var A:Array');
1198
AddCompilerFunction('Pred','X:Ordinal', 'Ordinal');
1199
AddCompilerProcedure('Read','');
1200
AddCompilerProcedure('ReadLn','');
1201
AddCompilerProcedure('ReadStr','S:String;var Args:Arguments');
1202
AddCompilerFunction('Seg','var X','LongInt');
1203
AddCompilerProcedure('SetLength','var S:String;NewLength:Integer');
1204
AddCompilerProcedure('SetLength','var A:Array;NewLength:Integer');
1205
AddCompilerFunction('SizeOf','Identifier','Integer');
1206
AddCompilerFunction('Slice','var A:Array;Count:Integer','Array');
1207
AddCompilerProcedure('Str','const X[:Width[:Decimals]];var S:String');
1208
AddCompilerFunction('Succ','X:Ordinal', 'Ordinal');
1209
AddCompilerFunction('TypeInfo','Identifier', 'Pointer');
1210
AddCompilerFunction('TypeOf','Identifier', 'Pointer');
1211
AddCompilerProcedure('Val','S:String;var V;var Code:Integer');
1212
AddCompilerFunction('Unaligned','var X','var'); // Florian declaration :)
1213
AddCompilerProcedure('Unpack','A:Array;var A:Array;N:Integer');
1214
AddCompilerProcedure('Write','Args:Arguments');
1215
AddCompilerProcedure('WriteLn','Args:Arguments');
1216
AddCompilerProcedure('WriteStr','var S:String;Args:Arguments');
1218
if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags)
1219
and Context.Tool.NodeIsInAMethod(Context.Node)
1220
and (not CurrentIdentifierList.HasIdentifier('Self','')) then begin
1221
// method body -> add 'Self'
1222
NewItem:=TIdentifierListItem.Create(
1231
CurrentIdentifierList.Add(NewItem);
1233
ProcNode:=Context.Node.GetNodeOfType(ctnProcedure);
1234
if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags)
1235
and Context.Tool.NodeIsFunction(ProcNode)
1236
and (not CurrentIdentifierList.HasIdentifier('Result','')) then begin
1237
// function body -> add 'Result'
1238
NewItem:=TIdentifierListItem.Create(
1247
CurrentIdentifierList.Add(NewItem);
1252
AddBaseType('Char');
1253
AddBaseType('WideChar');
1254
AddBaseType('Real');
1255
AddBaseType('Single');
1256
AddBaseType('Double');
1257
AddBaseType('Extended');
1258
AddBaseType('CExtended');
1259
AddBaseType('Currency');
1260
AddBaseType('Comp');
1261
AddBaseType('Int64');
1262
AddBaseType('Cardinal');
1263
AddBaseType('QWord');
1264
AddBaseType('Boolean');
1265
AddBaseType('ByteBool');
1266
AddBaseType('WordBool');
1267
AddBaseType('LongBool');
1268
AddBaseType('QWordBool');
1269
AddBaseType('String');
1270
AddBaseType('AnsiString');
1271
AddBaseType('ShortString');
1272
AddBaseType('WideString');
1273
AddBaseType('UnicodeString');
1274
AddBaseType('Pointer');
1275
AddBaseType('Word');
1276
AddBaseType('SmallInt');
1277
AddBaseType('ShortInt');
1278
AddBaseType('Byte');
1279
if not (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then begin
1280
AddBaseType('File');
1281
AddBaseType('Text');
1283
AddBaseConstant('Nil');
1284
AddBaseConstant('True');
1285
AddBaseConstant('False');
1288
HidddnUnits:=Scanner.GetHiddenUsedUnits;
1289
if HidddnUnits<>'' then begin
1290
p:=PChar(HidddnUnits);
1291
while p^<>#0 do begin
1292
while p^=',' do inc(p);
1293
if GetIdentLen(p)>0 then
1295
while not (p^ in [',',#0]) do inc(p);
1300
procedure TIdentCompletionTool.GatherUsefulIdentifiers(CleanPos: integer;
1301
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
1303
NewItem: TIdentifierListItem;
1304
PropertyName: String;
1306
while (CleanPos>1) and (IsIdentChar[Src[CleanPos-1]]) do dec(CleanPos);
1307
GatherPredefinedIdentifiers(CleanPos,Context,BeautifyCodeOptions);
1308
if Context.Node.Desc=ctnProperty then begin
1309
PropertyName:=ExtractPropName(Context.Node,false);
1310
//debugln('TIdentCompletionTool.GatherUsefulIdentifiers Property ',PropertyName);
1311
MoveCursorToCleanPos(CleanPos);
1313
if UpAtomIs('READ') then begin
1314
// add the default class completion 'read' specifier function
1315
NewItem:=TIdentifierListItem.Create(
1316
icompUnknown,true,0,
1317
CurrentIdentifierList.CreateIdentifier(
1318
BeautifyCodeOptions.PropertyReadIdentPrefix+PropertyName),
1319
0,nil,nil,ctnProcedure);
1320
CurrentIdentifierList.Add(NewItem);
1322
if UpAtomIs('WRITE') then begin
1323
// add the default class completion 'write' specifier function
1324
NewItem:=TIdentifierListItem.Create(
1325
icompUnknown,true,0,
1326
CurrentIdentifierList.CreateIdentifier(
1327
BeautifyCodeOptions.PropertyWriteIdentPrefix+PropertyName),
1328
0,nil,nil,ctnProcedure);
1329
CurrentIdentifierList.Add(NewItem);
1331
if (UpAtomIs('READ') or UpAtomIs('WRITE'))
1332
and (Context.Tool.FindClassOrInterfaceNode(Context.Node)<>nil)
1334
// add the default class completion 'read'/'write' specifier variable
1335
NewItem:=TIdentifierListItem.Create(
1336
icompUnknown,true,0,
1337
CurrentIdentifierList.CreateIdentifier(
1338
BeautifyCodeOptions.PrivateVariablePrefix+PropertyName),
1339
0,nil,nil,ctnVarDefinition);
1340
CurrentIdentifierList.Add(NewItem);
1342
if UpAtomIs('STORED') then begin
1343
// add the default class completion 'stored' specifier function
1344
NewItem:=TIdentifierListItem.Create(
1345
icompUnknown,true,0,
1346
CurrentIdentifierList.CreateIdentifier(
1347
PropertyName+BeautifyCodeOptions.PropertyStoredIdentPostfix),
1348
0,nil,nil,ctnProcedure);
1349
CurrentIdentifierList.Add(NewItem);
1354
procedure TIdentCompletionTool.GatherUnitnames;
1356
procedure GatherUnitsFromSet;
1358
// collect all unit files in fpc unit paths
1359
DirectoryCache.IterateFPCUnitsInSet(@AddToTreeOfUnitFileInfo);
1363
UnitPath, SrcPath: string;
1365
ANode: TAVLTreeNode;
1366
UnitFileInfo: TUnitFileInfo;
1367
NewItem: TIdentifierListItem;
1370
CurSourceName: String;
1374
GatherUnitAndSrcPath(UnitPath,SrcPath);
1375
//DebugLn('TIdentCompletionTool.GatherUnitnames UnitPath="',UnitPath,'" SrcPath="',SrcPath,'"');
1376
BaseDir:=ExtractFilePath(MainFilename);
1377
FIDTTreeOfUnitFiles:=nil;
1379
// search in unitpath
1380
UnitExt:='pp;pas;ppu';
1381
if Scanner.CompilerMode=cmMacPas then
1382
UnitExt:=UnitExt+';p';
1383
GatherUnitFiles(BaseDir,UnitPath,UnitExt,false,true,FIDTTreeOfUnitFiles);
1384
// search in srcpath
1386
if Scanner.CompilerMode=cmMacPas then
1387
SrcExt:=SrcExt+';p';
1388
GatherUnitFiles(BaseDir,SrcPath,SrcExt,false,true,FIDTTreeOfUnitFiles);
1392
CurSourceName:=GetSourceName;
1393
ANode:=FIDTTreeOfUnitFiles.FindLowest;
1394
while ANode<>nil do begin
1395
UnitFileInfo:=TUnitFileInfo(ANode.Data);
1396
if CompareIdentifiers(PChar(Pointer(UnitFileInfo.FileUnitName)),
1397
PChar(Pointer(CurSourceName)))<>0
1399
NewItem:=TIdentifierListItem.Create(
1400
icompCompatible,true,0,
1401
CurrentIdentifierList.CreateIdentifier(UnitFileInfo.FileUnitName),
1403
CurrentIdentifierList.Add(NewItem);
1405
ANode:=FIDTTreeOfUnitFiles.FindSuccessor(ANode);
1408
FreeTreeOfUnitFiles(FIDTTreeOfUnitFiles);
1412
procedure TIdentCompletionTool.GatherSourceNames(const Context: TFindContext);
1414
procedure Add(const SrcName: string);
1416
NewItem: TIdentifierListItem;
1418
NewItem:=TIdentifierListItem.Create(
1420
CurrentIdentifierList.CreateIdentifier(SrcName),
1421
0,nil,nil,Context.Node.Desc);
1422
CurrentIdentifierList.Add(NewItem);
1426
NewSourceName: String;
1427
FileSourceName: String;
1429
// add the unitname as in the filename and as in the source
1430
FileSourceName:=ExtractFilenameOnly(MainFilename);
1431
NewSourceName:=GetSourceName(false);
1432
//DebugLn('TIdentCompletionTool.GatherSourceNames FileSourceName=',FileSourceName,' NewSourceName=',NewSourceName);
1433
if (FileSourceName<>lowercase(FileSourceName)) then begin
1434
// the file is not written lowercase => case is important, ignore source name
1435
Add(FileSourceName);
1436
end else if (SysUtils.CompareText(NewSourceName,FileSourceName)<>0) then begin
1437
// source name is not correct => only use file name
1438
Add(FileSourceName);
1439
end else if NewSourceName=FileSourceName then begin
1440
// both are the same => add only one
1441
Add(FileSourceName);
1443
// both are valid, just different in case
1444
// the filename is written lowercase
1445
// => prefer the source name
1450
procedure TIdentCompletionTool.GatherContextKeywords(
1451
const Context: TFindContext; CleanPos: integer;
1452
BeautifyCodeOptions: TBeautifyCodeOptions);
1454
TPropertySpecifier = (
1455
psIndex,psRead,psWrite,psStored,psImplements,psDefault,psNoDefault
1457
TPropertySpecifiers = set of TPropertySpecifier;
1459
procedure Add(Keyword: string);
1461
NewItem: TIdentifierListItem;
1463
KeyWord:=BeautifyCodeOptions.BeautifyKeyWord(Keyword);
1464
NewItem:=TIdentifierListItem.Create(
1466
CurrentIdentifierList.CreateIdentifier(Keyword),
1467
1000,nil,nil,ctnNone);
1468
include(NewItem.Flags,iliKeyword);
1469
CurrentIdentifierList.Add(NewItem);
1472
procedure AddSpecifiers(Forbidden: TPropertySpecifiers);
1474
if not (psIndex in Forbidden) then Add('index');
1475
if not (psRead in Forbidden) then Add('read');
1476
if not (psWrite in Forbidden) then Add('write');
1477
if not (psStored in Forbidden) then Add('stored');
1478
if not (psImplements in Forbidden) then Add('implements');
1479
if not (psDefault in Forbidden) then Add('default');
1480
if not (psNoDefault in Forbidden) then Add('nodefault');
1483
procedure CheckProperty(PropNode: TCodeTreeNode);
1485
Forbidden: TPropertySpecifiers;
1487
if not MoveCursorToPropType(PropNode) then exit;
1488
if CleanPos<CurPos.EndPos then exit;
1490
if CurPos.Flag=cafPoint then begin
1492
if CurPos.Flag<>cafWord then exit;
1497
if CleanPos<=CurPos.EndPos then begin
1498
AddSpecifiers(Forbidden);
1501
if (not (psIndex in Forbidden)) and UpAtomIs('INDEX') then begin
1503
Include(Forbidden,psIndex);
1504
end else if (not (psRead in Forbidden)) and UpAtomIs('READ') then begin
1506
Forbidden:=Forbidden+[psIndex..psRead];
1507
end else if (not (psWrite in Forbidden)) and UpAtomIs('WRITE') then begin
1509
Forbidden:=Forbidden+[psIndex..psWrite];
1510
end else if (not (psImplements in Forbidden)) and UpAtomIs('IMPLEMENTS')
1514
end else if (not (psStored in Forbidden)) and UpAtomIs('STORED') then
1517
Forbidden:=Forbidden+[psIndex..psImplements];
1518
end else if (not (psDefault in Forbidden)) and UpAtomIs('DEFAULT') then
1522
end else if (not (psNoDefault in Forbidden)) and UpAtomIs('NODEFAULT') then
1526
end else if CurPos.Flag in [cafRoundBracketOpen,cafEdgedBracketOpen] then begin
1527
if not ReadTilBracketClose(false) then exit;
1530
until (CleanPos<CurPos.StartPos) or (CurPos.EndPos>SrcLen);
1533
procedure AddMethodSpecifiers;
1537
for i:=0 to IsKeyWordMethodSpecifier.Count-1 do
1538
Add(IsKeyWordMethodSpecifier.GetItem(i).KeyWord+';');
1542
Node: TCodeTreeNode;
1543
SubNode: TCodeTreeNode;
1544
NodeInFront: TCodeTreeNode;
1546
NodeBehind: TCodeTreeNode;
1549
//debugln(['TIdentCompletionTool.GatherContextKeywords ',Node.DescAsString]);
1551
ReadPriorAtomSafe(CleanPos);
1552
//debugln(['TIdentCompletionTool.GatherContextKeywords prioratom=',CleanPosToStr(CurPos.StartPos),'=',GetAtom(CurPos)]);
1554
if CurPos.StartPos>0 then
1555
NodeInFront:=FindDeepestNodeAtPos(CurPos.StartPos,false);
1558
MoveCursorToCleanPos(CleanPos);
1560
//debugln(['TIdentCompletionTool.GatherContextKeywords nextatom=',CleanPosToStr(CurPos.StartPos),'=',GetAtom(CurPos)]);
1561
if CurPos.StartPos>CleanPos then
1562
NodeBehind:=FindDeepestNodeAtPos(CurPos.StartPos,false);
1564
//debugln(['TIdentCompletionTool.GatherContextKeywords Node=',Node.DescAsString,' NodeInFront=',NodeInFront.DescAsString,' NodeBehind=',NodeBehind.DescAsString]);
1567
ctnClass,ctnObject,ctnRecordType,ctnObjCCategory,ctnObjCClass,
1568
ctnClassPrivate,ctnClassProtected,ctnClassPublic,ctnClassPublished:
1577
if (Node.Desc=ctnClass) or (Node.Parent.Desc=ctnClass) then begin
1581
if (Node.Desc=ctnRecordType) or (Node.Parent.Desc=ctnRecordType) then begin
1584
if (Node.LastChild<>nil) and (CleanPos>Node.LastChild.StartPos)
1585
and (Node.LastChild.EndPos>Node.LastChild.StartPos)
1586
and (Node.LastChild.EndPos<Srclen) then begin
1587
//debugln(['TIdentCompletionTool.GatherContextKeywords end of class section ',dbgstr(copy(Src,Node.LastChild.EndPos-10,10))]);
1588
SubNode:=Node.LastChild;
1589
if SubNode.Desc=ctnProperty then begin
1590
CheckProperty(SubNode);
1593
if NodeInFront<>nil then begin
1594
if NodeInFront.Desc=ctnProcedure then
1595
AddMethodSpecifiers;
1599
ctnClassInterface,ctnDispinterface,ctnObjCProtocol,ctnCPPClass:
1605
ctnInterface,ctnImplementation:
1607
if (Node.FirstChild=nil)
1608
or ((Node.FirstChild.Desc<>ctnUsesSection)
1609
and (Node.FirstChild.StartPos>=CleanPos))
1617
Add('resourcestring');
1618
if Node.Desc=ctnInterface then begin
1622
or (NodeBehind.Desc in [ctnInitialization,ctnFinalization,ctnEndPoint,ctnBeginBlock])
1624
if Node.Desc=ctnInterface then
1625
Add('implementation');
1626
Add('initialization');
1627
Add('finalization');
1633
or (NodeBehind.Desc in [ctnInitialization,ctnFinalization,ctnEndPoint,ctnBeginBlock])
1635
Add('finalization');
1651
MoveCursorBehindProcName(Node);
1653
while (p>=1) and (Src[p] in [' ',#9]) do dec(p);
1655
AddMethodSpecifiers;
1659
if Node.Parent.Desc in [ctnClass,ctnObject,ctnRecordType,ctnObjCCategory,ctnObjCClass]
1660
+AllClassBaseSections
1669
if [cmsObjectiveC1,cmsObjectiveC2]*Scanner.CompilerModeSwitches<>[] then
1674
if (Node.Desc=ctnClass) or (Node.Parent.Desc=ctnClass) then begin
1678
if (Node.Desc=ctnRecordType) or (Node.Parent.Desc=ctnRecordType) then begin
1683
ctnTypeSection,ctnVarSection,ctnConstSection,ctnLabelSection,ctnResStrSection,
1684
ctnLibrary,ctnProgram:
1689
Add('resourcestring');
1693
if Node.Desc=ctnLibrary then begin
1694
Add('initialization');
1695
Add('finalization');
1701
CheckProperty(Node);
1706
procedure TIdentCompletionTool.InitCollectIdentifiers(
1707
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList);
1709
StartContext: TFindContext;
1711
if IdentifierList=nil then IdentifierList:=TIdentifierList.Create;
1712
CurrentIdentifierList:=IdentifierList;
1713
CurrentIdentifierList.Clear;
1714
FLastGatheredIdentParent:=nil;
1715
FLastGatheredIdentLevel:=0;
1716
CurrentIdentifierList.StartContextPos:=CursorPos;
1717
StartContext := CurrentIdentifierList.StartContext;
1718
StartContext.Tool := Self;
1719
CurrentIdentifierList.StartContext:=StartContext;
1722
procedure TIdentCompletionTool.ParseSourceTillCollectionStart(
1723
const CursorPos: TCodeXYPosition; out CleanCursorPos: integer;
1724
out CursorNode: TCodeTreeNode; out IdentStartPos, IdentEndPos: integer);
1726
StartContext: TFindContext;
1727
ContextPos: Integer;
1736
DebugLn(['TIdentCompletionTool.ParseSourceTillCollectionStart A CursorPos=',dbgs(CursorPos)]);
1738
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
1739
[btSetIgnoreErrorPos]);
1741
// find node at position
1742
ContextPos:=CleanCursorPos;
1743
// The context node might be in front of the CleanCursorPos
1744
// For example: A.|end; In this case the statement ends at the point.
1745
// Check the atom in front
1746
ReadPriorAtomSafe(CleanCursorPos);
1747
if (CurPos.Flag<>cafNone) then begin
1748
ContextPos:=CurPos.EndPos;
1749
if (CurPos.Flag in [cafPoint,cafRoundBracketOpen,cafEdgedBracketOpen])
1750
or UpAtomIs('INHERITED') then
1751
ContextPos:=CurPos.StartPos;
1754
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(ContextPos,true);
1755
if CurrentIdentifierList<>nil then begin
1756
StartContext:=CurrentIdentifierList.StartContext;
1757
StartContext.Node:=CursorNode;
1758
CurrentIdentifierList.StartContext:=StartContext;
1761
// get identifier position
1762
GetIdentStartEndAtPosition(Src,CleanCursorPos,IdentStartPos,IdentEndPos);
1763
//DebugLn(['TIdentCompletionTool.ParseSourceTillCollectionStart ',dbgstr(copy(Src,IdentStartPos,10)),' CursorPos.X=',CursorPos.X,' LineLen=',CursorPos.Code.GetLineLength(CursorPos.Y-1),' ',CursorPos.Code.getline(CursorPos.Y-1)]);
1764
if CursorPos.X>CursorPos.Code.GetLineLength(CursorPos.Y-1)+1 then
1765
IdentStartPos:=IdentEndPos;
1768
function TIdentCompletionTool.FindIdentifierStartPos(
1769
const CursorPos: TCodeXYPosition): TCodeXYPosition;
1772
IdentStartPos, IdentEndPos: integer;
1774
CursorPos.Code.LineColToPosition(CursorPos.Y,CursorPos.X,p);
1776
RaiseException(ctsCursorPosOutsideOfCode);
1777
if CursorPos.X<=CursorPos.Code.GetLineLength(CursorPos.Y-1)+1 then begin
1778
GetIdentStartEndAtPosition(CursorPos.Code.Source,p,IdentStartPos,IdentEndPos);
1784
if IdentStartPos>0 then
1785
dec(Result.X,p-IdentStartPos);
1786
//DebugLn(['TIdentCompletionTool.FindIdentifierStartPos ',dbgstr(copy(CursorPos.Code.Source,IdentStartPos,20))]);
1789
procedure TIdentCompletionTool.FindCollectionContext(
1790
Params: TFindDeclarationParams; IdentStartPos: integer;
1791
CursorNode: TCodeTreeNode;
1792
out GatherContext: TFindContext;
1793
out ContextExprStartPos: LongInt;
1794
out StartInSubContext: Boolean);
1796
function GetContextExprStartPos(IdentStartPos: integer;
1797
ContextNode: TCodeTreeNode): integer;
1799
MoveCursorToCleanPos(IdentStartPos);
1801
if (CurPos.Flag=cafPoint)
1802
or UpAtomIs('INHERITED') then begin
1803
Result:=FindStartOfTerm(IdentStartPos,NodeTermInType(ContextNode));
1804
if Result<ContextNode.StartPos then
1805
Result:=ContextNode.StartPos;
1807
Result:=IdentStartPos;
1808
MoveCursorToCleanPos(Result);
1810
case ContextNode.Desc of
1812
// check for special property keywords
1813
if WordIsPropertySpecifier.DoItCaseInsensitive(Src,
1814
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
1816
// do not resolve property specifiers
1817
Result:=IdentStartPos;
1822
ExprType: TExpressionType;
1823
IgnoreCurContext: Boolean;
1825
GatherContext:=CreateFindContext(Self,CursorNode);
1827
IgnoreCurContext:=false;
1828
//DebugLn(['TIdentCompletionTool.FindCollectionContext IdentStartPos=',dbgstr(copy(Src,IdentStartPos,20)),' ',CursorNode.DescAsString]);
1829
ContextExprStartPos:=GetContextExprStartPos(IdentStartPos,CursorNode);
1830
if GatherContext.Node.Desc=ctnWithVariable then begin
1831
if GatherContext.Node.PriorBrother<>nil then
1832
GatherContext.Node:=GatherContext.Node.PriorBrother
1834
GatherContext.Node:=GatherContext.Node.Parent;
1836
else if (GatherContext.Node.GetNodeOfType(ctnClassInheritance)<>nil) then
1838
while not (GatherContext.Node.Desc in AllClasses) do
1839
GatherContext.Node:=GatherContext.Node.Parent;
1840
GatherContext.Node:=GatherContext.Node.Parent;
1841
IgnoreCurContext:=true;
1842
end else if GatherContext.Node.Desc=ctnIdentifier then begin
1843
IgnoreCurContext:=true;
1846
StartInSubContext:=false;
1847
//DebugLn(['TIdentCompletionTool.FindCollectionContext ContextExprStartPos=',ContextExprStartPos,' "',dbgstr(copy(Src,ContextExprStartPos,20)),'" IdentStartPos="',dbgstr(copy(Src,IdentStartPos,20)),'" Gather=',FindContextToString(GatherContext)]);
1848
if ContextExprStartPos<IdentStartPos then begin
1849
MoveCursorToCleanPos(IdentStartPos);
1850
Params.ContextNode:=CursorNode;
1851
Params.SetIdentifier(Self,nil,nil);
1852
Params.Flags:=[fdfExceptionOnNotFound,
1853
fdfSearchInParentNodes,fdfSearchInAncestors];
1854
if IgnoreCurContext then
1855
Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode];
1856
ExprType:=FindExpressionTypeOfTerm(ContextExprStartPos,IdentStartPos,
1858
if (ExprType.Desc=xtContext) then begin
1859
GatherContext:=ExprType.Context;
1860
StartInSubContext:=true;
1865
function TIdentCompletionTool.CollectAllContexts(
1866
Params: TFindDeclarationParams; const FoundContext: TFindContext
1867
): TIdentifierFoundResult;
1869
Result:=ifrProceedSearch;
1870
if FoundContext.Node=nil then exit;
1871
//DebugLn(['TIdentCompletionTool.CollectAllContexts ',FoundContext.Node.DescAsString]);
1872
case FoundContext.Node.Desc of
1875
//DebugLn('TIdentCompletionTool.CollectAllContexts CurrentContexts.ProcNameAtom.StartPos=',dbgs(CurrentIdentifierContexts.ProcNameAtom.StartPos));
1876
if (CurrentIdentifierContexts.ProcName='') then exit;
1877
FoundContext.Tool.MoveCursorToProcName(FoundContext.Node,true);
1878
//DebugLn(['TIdentCompletionTool.CollectAllContexts ProcName=',GetIdentifier(@FoundContext.Tool.Src[FoundContext.Tool.CurPos.StartPos])]);
1879
if not FoundContext.Tool.CompareSrcIdentifiers(
1880
FoundContext.Tool.CurPos.StartPos,
1881
PChar(CurrentIdentifierContexts.ProcName))
1886
if (CurrentIdentifierContexts.ProcName='') then exit;
1887
FoundContext.Tool.MoveCursorToPropName(FoundContext.Node);
1888
if not FoundContext.Tool.CompareSrcIdentifiers(
1889
FoundContext.Tool.CurPos.StartPos,
1890
PChar(CurrentIdentifierContexts.ProcName))
1895
if (CurrentIdentifierContexts.ProcName='') then exit;
1896
if not FoundContext.Tool.CompareSrcIdentifiers(
1897
FoundContext.Node.StartPos,
1898
PChar(CurrentIdentifierContexts.ProcName))
1904
//DebugLn(['TIdentCompletionTool.CollectAllContexts add ',FoundContext.Node.DescAsString]);
1905
AddCollectionContext(FoundContext.Tool,FoundContext.Node);
1908
procedure TIdentCompletionTool.AddCollectionContext(Tool: TFindDeclarationTool;
1909
Node: TCodeTreeNode);
1911
if CurrentIdentifierContexts=nil then
1912
CurrentIdentifierContexts:=TCodeContextInfo.Create;
1913
CurrentIdentifierContexts.Add(CreateExpressionType(xtContext,xtNone,
1914
CreateFindContext(Tool,Node)));
1915
//DebugLn('TIdentCompletionTool.AddCollectionContext ',Node.DescAsString,' ',ExtractNode(Node,[]));
1918
procedure TIdentCompletionTool.InitFoundMethods;
1920
if FIDTFoundMethods<>nil then ClearFoundMethods;
1921
FIDTFoundMethods:=TAVLTree.Create(@CompareCodeTreeNodeExt);
1924
procedure TIdentCompletionTool.ClearFoundMethods;
1926
if FIDTFoundMethods=nil then exit;
1927
FreeAndNil(FIDTFoundMethods);
1930
function TIdentCompletionTool.CollectMethods(
1931
Params: TFindDeclarationParams; const FoundContext: TFindContext
1932
): TIdentifierFoundResult;
1935
AVLNode: TAVLTreeNode;
1936
NodeExt: TCodeTreeNodeExtension;
1938
// proceed searching ...
1939
Result:=ifrProceedSearch;
1941
{$IFDEF ShowFoundIdents}
1942
//if FoundContext.Tool=Self then
1943
DebugLn('::: COLLECT IDENT ',FoundContext.Node.DescAsString,
1944
' "',StringToPascalConst(copy(FoundContext.Tool.Src,FoundContext.Node.StartPos,50)),'"');
1947
if FoundContext.Node.Desc=ctnProcedure then begin
1948
ProcText:=FoundContext.Tool.ExtractProcHead(FoundContext.Node,
1949
[phpWithoutClassKeyword,phpWithHasDefaultValues]);
1950
AVLNode:=FindCodeTreeNodeExtAVLNode(FIDTFoundMethods,ProcText);
1951
if AVLNode<>nil then begin
1952
// method is overriden => ignore
1955
NodeExt:=TCodeTreeNodeExtension.Create;
1956
NodeExt.Node:=FoundContext.Node;
1957
NodeExt.Data:=FoundContext.Tool;
1958
NodeExt.Txt:=ProcText;
1959
FIDTFoundMethods.Add(NodeExt);
1964
function TIdentCompletionTool.IsInCompilerDirective(CursorPos: TCodeXYPosition
1967
procedure Key(const DirectiveName: string);
1969
NewItem: TIdentifierListItem;
1971
NewItem:=TIdentifierListItem.Create(
1973
CurrentIdentifierList.CreateIdentifier(DirectiveName),
1974
1000,nil,nil,ctnNone);
1975
include(NewItem.Flags,iliKeyword);
1976
CurrentIdentifierList.Add(NewItem);
1979
procedure AddMacros;
1981
Macros: TStringToStringTree;
1982
StrItem: PStringToStringTreeItem;
1984
procedure Add(e: TExpressionEvaluator);
1988
for i:=0 to e.Count-1 do
1989
Macros[e.Names(i)]:=e.Values(i);
1993
Macros:=TStringToStringTree.Create(false);
1995
Add(Scanner.InitialValues);
1996
Add(Scanner.Values);
1997
for StrItem in Macros do
2008
InnerStart: Integer;
2010
ms: TCompilerModeSwitch;
2013
Line:=CursorPos.Code.GetLine(CursorPos.Y-1);
2015
while p<=length(Line) do begin
2016
p:=FindNextCompilerDirective(Line,p,Scanner.NestedComments);
2017
if p>length(Line) then exit;
2018
EndPos:=FindCommentEnd(Line,p,Scanner.NestedComments);
2019
if (CursorPos.X>p) and (CursorPos.X<EndPos) then begin
2023
if Line[InnerStart]='{' then
2027
//debugln(['TIdentCompletionTool.IsInCompilerDirective InnerStart=',InnerStart,' X=',CursorPos.X]);
2028
if (InnerStart=CursorPos.X)
2029
or ((CursorPos.X>=InnerStart) and (InnerStart<=length(Line))
2030
and (CursorPos.X<=InnerStart+GetIdentLen(@Line[InnerStart])))
2033
Key('ALIGNASSERTIONS');
2039
Key('CHECKPOINTER');
2052
Key('EXTENDEDSYNTAX');
2063
Key('IMPLICITEXCEPTIONS');
2071
Key('LINKFRAMEWORK');
2073
Key('LOCALSYMBOLS');
2076
Key('MAXFPUREGISTERS');
2085
Key('OBJECTCHECKS');
2087
Key('OPTIMIZATION');
2088
Key('OUTPUT_FORMAT');
2090
Key('OVERFLOWCHECKS');
2098
Key('REFERENCEINFO');
2106
Key('VARSTRINGCHECKS');
2110
Key('WRITABLECONST');
2111
end else if InnerStart<=length(Line) then begin
2112
Directive:=lowercase(GetIdentifier(@Line[InnerStart]));
2113
if (Directive='ifdef')
2114
or (Directive='ifndef')
2116
or (Directive='elseif')
2117
or (Directive='ifc')
2120
end else if Directive='modeswitch' then begin
2121
for ms:=low(TCompilerModeSwitch) to high(TCompilerModeSwitch) do
2122
Key(lowercase(CompilerModeSwitchNames[ms]));
2131
function TIdentCompletionTool.GatherAvailableUnitNames(const CursorPos: TCodeXYPosition;
2132
var IdentifierList: TIdentifierList): Boolean;
2137
InitCollectIdentifiers(CursorPos, IdentifierList);
2143
CurrentIdentifierList:=nil;
2147
function TIdentCompletionTool.GatherIdentifiers(
2148
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList;
2149
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
2151
CleanCursorPos, IdentStartPos, IdentEndPos: integer;
2152
CursorNode: TCodeTreeNode;
2153
Params: TFindDeclarationParams;
2154
GatherContext: TFindContext;
2155
ContextExprStartPos: Integer;
2156
StartInSubContext: Boolean;
2157
StartPosOfVariable: LongInt;
2158
CursorContext: TFindContext;
2159
IdentStartXY: TCodeXYPosition;
2160
InFrontOfDirective: Boolean;
2162
procedure CheckProcedureDeclarationContext;
2164
Node: TCodeTreeNode;
2167
//DebugLn(['CheckProcedureDeclarationContext ',CursorNode.DescAsString]);
2170
if (Node.Parent<>nil)
2171
and (Node.Parent.Desc in AllClassSections)
2172
and (Node.Desc=ctnVarDefinition)
2173
and (CurrentIdentifierList.StartAtomBehind.Flag<>cafColon) then begin
2174
{ cursor is at a class variable definition without type
2183
else if (((Node.Desc=ctnProcedure) and (not NodeIsMethodBody(Node)))
2184
or ((Node.Desc=ctnProcedureHead) and (not NodeIsMethodBody(Node.Parent))))
2185
and (not (CurrentIdentifierList.StartAtomBehind.Flag
2186
in [cafEdgedBracketOpen,cafRoundBracketOpen]))
2188
// for example: procedure DoSomething|
2191
else if Node.Desc in (AllClassBaseSections+AllSourceTypes
2192
+[ctnInterface,ctnImplementation])
2194
//DebugLn(['TIdentCompletionTool.CheckProcedureDeclarationContext ilcfCanProcDeclaration']);
2198
CurrentIdentifierList.ContextFlags:=
2199
CurrentIdentifierList.ContextFlags+[ilcfCanProcDeclaration];
2205
ActivateGlobalWriteLock;
2206
Params:=TFindDeclarationParams.Create;
2208
InitCollectIdentifiers(CursorPos,IdentifierList);
2209
IdentStartXY:=FindIdentifierStartPos(CursorPos);
2210
if IsInCompilerDirective(IdentStartXY) then exit(true);
2212
ParseSourceTillCollectionStart(IdentStartXY,CleanCursorPos,CursorNode,
2213
IdentStartPos,IdentEndPos);
2214
if CleanCursorPos=0 then ;
2215
if IdentStartPos>0 then begin
2216
MoveCursorToCleanPos(IdentStartPos);
2218
CurrentIdentifierList.StartAtom:=CurPos;
2223
DebugLn('TIdentCompletionTool.GatherIdentifiers B',
2224
' CleanCursorPos=',dbgs(CleanCursorPos),
2225
' IdentStartPos=',dbgs(IdentStartPos),' IdentEndPos=',dbgs(IdentEndPos),
2226
' Ident=',copy(Src,IdentStartPos,IdentEndPos-IdentStartPos));
2228
GatherContext:=CreateFindContext(Self,CursorNode);
2229
CurrentIdentifierList.NewMemberVisibility:=GetClassVisibility(CursorNode);
2230
if CursorNode.Desc in [ctnUsesSection,ctnUseUnit] then begin
2232
MoveCursorToCleanPos(IdentEndPos);
2234
if (CurPos.Flag=cafWord) and (not UpAtomIs('IN')) then begin
2236
CurrentIdentifierList.ContextFlags:=
2237
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndComma];
2239
end else if (CursorNode.Desc in AllSourceTypes)
2240
and (PositionsInSameLine(Src,CursorNode.StartPos,IdentStartPos)) then begin
2241
GatherSourceNames(GatherContext);
2243
FindCollectionContext(Params,IdentStartPos,CursorNode,
2244
GatherContext,ContextExprStartPos,StartInSubContext);
2246
// find class and ancestors if existing (needed for protected identifiers)
2247
if GatherContext.Tool = Self then
2248
FindContextClassAndAncestors(IdentStartXY, FICTClassAndAncestors);
2250
CursorContext:=CreateFindContext(Self,CursorNode);
2251
GatherContextKeywords(CursorContext,IdentStartPos,BeautifyCodeOptions);
2253
// search and gather identifiers in context
2254
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
2256
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
2257
GatherContext.Tool.MainFilename,
2258
' ',GatherContext.Node.DescAsString,
2259
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
2262
// gather all identifiers in context
2263
Params.ContextNode:=GatherContext.Node;
2264
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
2265
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
2266
if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then
2267
Include(Params.Flags,fdfIgnoreUsedUnits);
2268
if not StartInSubContext then
2269
Include(Params.Flags,fdfSearchInParentNodes);
2270
if Params.ContextNode.Desc in AllClasses then
2271
Exclude(Params.Flags,fdfSearchInParentNodes);
2273
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
2275
CurrentIdentifierList.Context:=GatherContext;
2276
if GatherContext.Node.Desc=ctnIdentifier then
2277
Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode];
2278
GatherContext.Tool.FindIdentifierInContext(Params);
2281
// check for incomplete context
2283
// context bracket level
2284
CurrentIdentifierList.StartBracketLvl:=
2285
GetBracketLvl(Src,CursorNode.StartPos,IdentStartPos,
2286
Scanner.NestedComments);
2287
if CursorNode.Desc in AllPascalStatements then begin
2288
CurrentIdentifierList.ContextFlags:=
2289
CurrentIdentifierList.ContextFlags+[ilcfStartInStatement];
2292
// context in front of
2293
StartPosOfVariable:=FindStartOfTerm(IdentStartPos,NodeTermInType(CursorNode));
2294
if StartPosOfVariable>0 then begin
2295
if StartPosOfVariable=IdentStartPos then begin
2296
// cursor is at start of an operand
2297
CurrentIdentifierList.ContextFlags:=
2298
CurrentIdentifierList.ContextFlags+[ilcfStartOfOperand];
2300
MoveCursorToCleanPos(IdentStartPos);
2302
if CurPos.Flag=cafPoint then
2303
// cursor is behind a point
2304
CurrentIdentifierList.ContextFlags:=
2305
CurrentIdentifierList.ContextFlags+[ilcfStartIsSubIdent];
2307
MoveCursorToCleanPos(StartPosOfVariable);
2309
CurrentIdentifierList.StartAtomInFront:=CurPos;
2310
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags)
2311
and (not IsDirtySrcValid) then
2314
if (CurPos.Flag in [cafSemicolon,cafEnd,cafColon])
2315
or UpAtomIs('BEGIN')
2316
or UpAtomIs('TRY') or UpAtomIs('FINALLY') or UpAtomIs('EXCEPT')
2317
or UpAtomIs('FOR') or UpAtomIs('DO') or UpAtomIs('THEN')
2318
or UpAtomIs('REPEAT') or UpAtomIs('ASM') or UpAtomIs('ELSE')
2320
CurrentIdentifierList.ContextFlags:=
2321
CurrentIdentifierList.ContextFlags+[ilcfStartOfStatement];
2323
// check if expression
2324
if UpAtomIs('IF') or UpAtomIs('CASE') or UpAtomIs('WHILE')
2325
or UpAtomIs('UNTIL')
2327
// todo: check at start of expression, not only in front of variable
2328
CurrentIdentifierList.ContextFlags:=
2329
CurrentIdentifierList.ContextFlags+[ilcfIsExpression];
2334
if (IdentEndPos<SrcLen) and (not IsDirtySrcValid) then begin
2335
MoveCursorToCleanPos(IdentEndPos);
2336
InFrontOfDirective:=(CurPos.StartPos<SrcLen) and (Src[CurPos.StartPos]='{')
2337
and (Src[CurPos.StartPos+1]='$');
2340
// check end of line
2341
if (not InFrontOfDirective)
2342
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)) then
2343
CurrentIdentifierList.ContextFlags:=
2344
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
2346
CurrentIdentifierList.StartAtomBehind:=CurPos;
2347
// check if a semicolon is needed or forbidden at the end
2348
if InFrontOfDirective
2349
or (CurrentIdentifierList.StartBracketLvl>0)
2350
or (CurPos.Flag in [cafSemicolon, cafEqual, cafColon, cafComma,
2351
cafPoint, cafRoundBracketOpen, cafRoundBracketClose,
2352
cafEdgedBracketOpen, cafEdgedBracketClose])
2353
or ((CurPos.Flag in [cafWord,cafNone])
2354
and (UpAtomIs('ELSE')
2359
or WordIsBinaryOperator.DoItCaseInsensitive(Src,
2360
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)))
2362
// do not add semicolon
2363
CurrentIdentifierList.ContextFlags:=
2364
CurrentIdentifierList.ContextFlags+[ilcfNoEndSemicolon];
2366
// check if in statement
2367
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then
2369
// check if a semicolon is needed at the end
2370
if (not (ilcfNoEndSemicolon in CurrentIdentifierList.ContextFlags))
2372
// check if a semicolon is needed at the end
2373
if (CurPos.Flag in [cafEnd])
2374
or WordIsBlockKeyWord.DoItCaseInsensitive(Src,
2375
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
2376
or ((CurPos.Flag=cafWord)
2377
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
2380
CurrentIdentifierList.ContextFlags:=
2381
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndSemicolon];
2385
// check missing 'do' after 'with'
2386
if CurrentIdentifierList.StartUpAtomInFrontIs('WITH')
2387
and (not CurrentIdentifierList.StartUpAtomBehindIs('DO'))
2388
and (CurrentIdentifierList.StartBracketLvl=0)
2389
and (not (CurrentIdentifierList.StartAtomBehind.Flag in
2390
[cafComma,cafPoint,cafRoundBracketOpen,cafEdgedBracketOpen]))
2391
and (not CurrentIdentifierList.StartUpAtomBehindIs('^'))
2393
CurrentIdentifierList.ContextFlags:=
2394
CurrentIdentifierList.ContextFlags+[ilcfNeedsDo];
2397
CurrentIdentifierList.ContextFlags:=
2398
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
2401
// check for procedure/method declaration context
2402
CheckProcedureDeclarationContext;
2404
// add useful identifiers
2406
DebugLn('TIdentCompletionTool.GatherIdentifiers G');
2408
GatherUsefulIdentifiers(IdentStartPos,CursorContext,BeautifyCodeOptions);
2413
FreeListOfPFindContext(FICTClassAndAncestors);
2414
FreeAndNil(FIDCTFoundPublicProperties);
2416
ClearIgnoreErrorAfter;
2417
DeactivateGlobalWriteLock;
2418
CurrentIdentifierList:=nil;
2421
DebugLn('TIdentCompletionTool.GatherIdentifiers END');
2425
function TIdentCompletionTool.FindCodeContext(const CursorPos: TCodeXYPosition;
2426
out CodeContexts: TCodeContextInfo): boolean;
2428
CleanCursorPos: integer;
2429
CursorNode: TCodeTreeNode;
2430
Params: TFindDeclarationParams;
2432
procedure AddPredefinedProcs(CurrentContexts: TCodeContextInfo;
2433
ProcNameAtom: TAtomPosition);
2435
procedure AddCompilerProc(const AProcName: string;
2436
const Params: string; const ResultType: string = '');
2439
Item: TCodeContextInfoItem;
2441
if CompareIdentifiers(PChar(AProcName),@Src[ProcNameAtom.StartPos])<>0
2443
i:=CurrentContexts.AddCompilerProc;
2444
Item:=CurrentContexts[i];
2445
Item.ProcName:=AProcName;
2446
Item.ResultType:=ResultType;
2447
Item.Params:=TStringList.Create;
2448
Item.Params.Delimiter:=';';
2449
Item.Params.StrictDelimiter:=true;
2450
Item.Params.DelimitedText:=Params;
2454
MoveCursorToAtomPos(ProcNameAtom);
2456
if (CurPos.Flag in [cafEnd,cafSemicolon,cafColon,
2457
cafRoundBracketOpen,cafEdgedBracketOpen])
2458
or UpAtomIs('BEGIN')
2459
or UpAtomIs('TRY') or UpAtomIs('FINALLY') or UpAtomIs('EXCEPT')
2460
or UpAtomIs('REPEAT') or UpAtomIs('ASM') then begin
2461
// see fpc/compiler/psystem.pp
2462
AddCompilerProc('Assert','Condition:Boolean;const Message:String');
2463
AddCompilerProc('Assigned','P:Pointer','Boolean');
2464
AddCompilerProc('Addr','var X','Pointer');
2465
AddCompilerProc('BitSizeOf','Identifier','Integer');
2466
AddCompilerProc('Concat','S1:String;S2:String[...;Sn:String]', 'String');
2467
AddCompilerProc('Copy','const S:String;FromPosition,Count:Integer', 'String');
2468
AddCompilerProc('Dec','var X:Ordinal;N:Integer=1');
2469
AddCompilerProc('Dispose','var X:Pointer');
2470
AddCompilerProc('Exclude','var S:Set;X:Ordinal');
2471
AddCompilerProc('Exit','ResultValue:Ordinal=Result');
2472
AddCompilerProc('Finalize','var X');
2473
AddCompilerProc('get_frame','','Pointer');
2474
AddCompilerProc('High','Arg:TypeOrVariable','Ordinal');
2475
AddCompilerProc('Inc','var X:Ordinal;N:Integer=1');
2476
AddCompilerProc('Include','var S:Set;X:Ordinal');
2477
AddCompilerProc('Initialize','var X');
2478
AddCompilerProc('Length','S:String','Integer');
2479
AddCompilerProc('Length','A:Array','Integer');
2480
AddCompilerProc('Low','Arg:TypeOrVariable','Ordinal');
2481
AddCompilerProc('New','var X:Pointer');
2482
AddCompilerProc('Ofs','var X','LongInt');
2483
AddCompilerProc('Ord','X:Ordinal', 'Integer');
2484
AddCompilerProc('Pack','A:Array;N:Integer;var A:Array');
2485
AddCompilerProc('Pred','X:Ordinal', 'Ordinal');
2486
AddCompilerProc('Read','');
2487
AddCompilerProc('ReadLn','');
2488
AddCompilerProc('ReadStr','S:String;var Args:Arguments');
2489
AddCompilerProc('Seg','var X','LongInt');
2490
AddCompilerProc('SetLength','var S:String;NewLength:Integer');
2491
AddCompilerProc('SetLength','var A:Array;NewLength:Integer');
2492
AddCompilerProc('SizeOf','Identifier','Integer');
2493
AddCompilerProc('Slice','var A:Array;Count:Integer','Array');
2494
AddCompilerProc('Str','const X[:Width[:Decimals]];var S:String');
2495
AddCompilerProc('Succ','X:Ordinal', 'Ordinal');
2496
AddCompilerProc('TypeInfo','Identifier', 'Pointer');
2497
AddCompilerProc('TypeOf','Identifier', 'Pointer');
2498
AddCompilerProc('Val','S:String;var V;var Code:Integer');
2499
AddCompilerProc('Unaligned','var X','var');
2500
AddCompilerProc('Unpack','A:Array;var A:Array;N:Integer');
2501
AddCompilerProc('Write','Args:Arguments');
2502
AddCompilerProc('WriteLn','Args:Arguments');
2503
AddCompilerProc('WriteStr','var S:String;Args:Arguments');
2507
function CheckContextIsParameter(var Ok: boolean): boolean;
2508
// returns true, on error or context is parameter
2510
VarNameAtom, ProcNameAtom: TAtomPosition;
2511
ParameterIndex: integer;
2512
GatherContext: TFindContext;
2513
ContextExprStartPos: LongInt;
2514
StartInSubContext: Boolean;
2517
// check if in a begin..end block
2518
if CursorNode.GetNodeOfTypes([ctnBeginBlock,ctnInitialization,ctnFinalization])=nil
2520
DebugLn(['TIdentCompletionTool.FindCodeContext.CheckContextIsParameter not in a begin block']);
2523
// check if cursor is in a parameter list
2524
if not CheckParameterSyntax(CursorNode, CleanCursorPos,
2525
VarNameAtom, ProcNameAtom, ParameterIndex)
2527
if VarNameAtom.StartPos=0 then ;
2528
//DebugLn(['TIdentCompletionTool.FindCodeContext.CheckContextIsParameter not in a parameter list']);
2531
//DebugLn('CheckContextIsParameter Variable=',GetAtom(VarNameAtom),' Proc=',GetAtom(ProcNameAtom),' ParameterIndex=',dbgs(ParameterIndex));
2533
// it is a parameter -> create context
2535
if CurrentIdentifierContexts=nil then
2536
CurrentIdentifierContexts:=TCodeContextInfo.Create;
2537
CurrentIdentifierContexts.Tool:=Self;
2538
CurrentIdentifierContexts.ParameterIndex:=ParameterIndex+1;
2539
CurrentIdentifierContexts.ProcNameAtom:=ProcNameAtom;
2540
CurrentIdentifierContexts.ProcName:=GetAtom(ProcNameAtom);
2542
AddPredefinedProcs(CurrentIdentifierContexts,ProcNameAtom);
2544
MoveCursorToAtomPos(ProcNameAtom);
2545
ReadNextAtom; // read opening bracket
2546
CurrentIdentifierContexts.StartPos:=CurPos.EndPos;
2547
// read closing bracket
2548
if ReadTilBracketClose(false) then
2549
CurrentIdentifierContexts.EndPos:=CurPos.StartPos
2551
CurrentIdentifierContexts.EndPos:=SrcLen+1;
2553
FindCollectionContext(Params,ProcNameAtom.StartPos,CursorNode,
2554
GatherContext,ContextExprStartPos,StartInSubContext);
2555
if ContextExprStartPos=0 then ;
2556
//DebugLn(['CheckContextIsParameter StartInSubContext=',StartInSubContext,' ',GatherContext.Node.DescAsString,' "',copy(GatherContext.Tool.Src,GatherContext.Node.StartPos-20,25),'"']);
2558
// gather declarations of all parameter lists
2559
Params.ContextNode:=GatherContext.Node;
2560
Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],@CollectAllContexts);
2561
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
2562
if not StartInSubContext then
2563
Include(Params.Flags,fdfSearchInParentNodes);
2564
CurrentIdentifierList.Context:=GatherContext;
2565
//DebugLn('CheckContextIsParameter searching procedures, properties and variables ...');
2566
GatherContext.Tool.FindIdentifierInContext(Params);
2567
//DebugLn('CheckContextIsParameter END');
2572
IdentifierList: TIdentifierList;
2573
IdentStartPos, IdentEndPos: integer;
2578
IdentifierList:=nil;
2579
CurrentIdentifierContexts:=CodeContexts;
2581
ActivateGlobalWriteLock;
2582
Params:=TFindDeclarationParams.Create;
2584
InitCollectIdentifiers(CursorPos,IdentifierList);
2585
ParseSourceTillCollectionStart(CursorPos,CleanCursorPos,CursorNode,
2586
IdentStartPos,IdentEndPos);
2587
if IdentStartPos=0 then ;
2588
if IdentEndPos=0 then ;
2590
// find class and ancestors if existing (needed for protected identifiers)
2591
FindContextClassAndAncestors(CursorPos,FICTClassAndAncestors);
2593
if CursorNode<>nil then begin
2594
if not CheckContextIsParameter(Result) then begin
2595
//DebugLn(['TIdentCompletionTool.FindCodeContext cursor not at parameter']);
2600
if CurrentIdentifierContexts=nil then begin
2602
AddCollectionContext(Self,CursorNode);
2607
if Result then begin
2608
CodeContexts:=CurrentIdentifierContexts;
2609
CurrentIdentifierContexts:=nil;
2611
FreeAndNil(CurrentIdentifierContexts);
2613
FreeListOfPFindContext(FICTClassAndAncestors);
2614
FreeAndNil(FIDCTFoundPublicProperties);
2616
ClearIgnoreErrorAfter;
2617
DeactivateGlobalWriteLock;
2618
FreeAndNil(CurrentIdentifierList);
2622
function TIdentCompletionTool.FindAbstractMethods(
2623
const CursorPos: TCodeXYPosition; out ListOfPCodeXYPosition: TFPList;
2624
SkipAbstractsInStartClass: boolean): boolean;
2626
CleanCursorPos: integer;
2627
CursorNode: TCodeTreeNode;
2628
Params: TFindDeclarationParams;
2629
AVLNode: TAVLTreeNode;
2630
NodeExt: TCodeTreeNodeExtension;
2631
ATool: TFindDeclarationTool;
2632
ANode: TCodeTreeNode;
2633
ProcXYPos: TCodeXYPosition;
2635
ClassNode: TCodeTreeNode;
2638
ListOfPCodeXYPosition:=nil;
2639
ActivateGlobalWriteLock;
2642
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
2643
[btSetIgnoreErrorPos]);
2645
// find node at position
2646
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos,true);
2648
// if cursor is on type node, find class node
2649
if CursorNode.Desc=ctnTypeDefinition then
2650
CursorNode:=CursorNode.FirstChild
2651
else if CursorNode.Desc=ctnGenericType then
2652
CursorNode:=CursorNode.LastChild
2654
CursorNode:=FindClassOrInterfaceNode(CursorNode);
2656
or (not (CursorNode.Desc in AllClassObjects))
2657
or ((CursorNode.SubDesc and ctnsForwardDeclaration)>0) then begin
2658
MoveCursorToCleanPos(CleanCursorPos);
2659
RaiseException('TIdentCompletionTool.FindAbstractMethods cursor is not in a class');
2661
ClassNode:=CursorNode;
2663
Params:=TFindDeclarationParams.Create;
2664
// gather all identifiers in context
2665
Params.ContextNode:=ClassNode;
2666
Params.SetIdentifier(Self,nil,@CollectMethods);
2667
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
2669
FindIdentifierInContext(Params);
2671
if FIDTFoundMethods<>nil then begin
2672
AVLNode:=FIDTFoundMethods.FindLowest;
2673
while AVLNode<>nil do begin
2674
NodeExt:=TCodeTreeNodeExtension(AVLNode.Data);
2675
ANode:=NodeExt.Node;
2676
ATool:=TFindDeclarationTool(NodeExt.Data);
2677
//DebugLn(['TIdentCompletionTool.FindAbstractMethods ',NodeExt.Txt,' ',ATool.ProcNodeHasSpecifier(ANode,psABSTRACT)]);
2679
if not ATool.ProcNodeHasSpecifier(ANode,psABSTRACT) then
2681
if SkipAbstractsInStartClass and (ANode.HasAsParent(ClassNode)) then
2683
if not Skip then begin
2684
if not ATool.CleanPosToCaret(ANode.StartPos,ProcXYPos) then
2685
raise Exception.Create('TIdentCompletionTool.FindAbstractMethods inconsistency');
2686
AddCodePosition(ListOfPCodeXYPosition,ProcXYPos);
2688
AVLNode:=FIDTFoundMethods.FindSuccessor(AVLNode);
2696
DeactivateGlobalWriteLock;
2700
function TIdentCompletionTool.GetValuesOfCaseVariable(
2701
const CursorPos: TCodeXYPosition; List: TStrings): boolean;
2703
CleanCursorPos: integer;
2704
CursorNode: TCodeTreeNode;
2705
CaseAtom: TAtomPosition;
2706
Params: TFindDeclarationParams;
2708
ExprType: TExpressionType;
2709
Node: TCodeTreeNode;
2710
Tool: TFindDeclarationTool;
2713
ActivateGlobalWriteLock;
2716
BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanCursorPos,
2717
[btSetIgnoreErrorPos]);
2719
// find node at position
2720
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos,true);
2722
// find keyword case
2723
MoveCursorToNodeStart(CursorNode);
2724
CaseAtom:=CleanAtomPosition;
2727
if UpAtomIs('CASE') then
2729
until (CurPos.EndPos>SrcLen) or (CurPos.EndPos>CleanCursorPos);
2730
if CaseAtom.StartPos<1 then exit;
2732
// find case variable
2733
EndPos:=FindEndOfExpression(CaseAtom.EndPos);
2734
if EndPos>CleanCursorPos then
2735
EndPos:=CleanCursorPos;
2736
//DebugLn(['TIdentCompletionTool.GetValuesOfCaseVariable Expr=',dbgstr(copy(Src,CaseAtom.EndPos,EndPos-CaseAtom.EndPos))]);
2738
Params:=TFindDeclarationParams.Create;
2739
Params.ContextNode:=CursorNode;
2740
Params.Flags:=fdfDefaultForExpressions+[fdfFunctionResult];
2741
ExprType:=FindExpressionTypeOfTerm(CaseAtom.EndPos,EndPos,Params,true);
2742
//DebugLn(['TIdentCompletionTool.GetValuesOfCaseVariable Type=',ExprTypeToString(ExprType)]);
2744
if ExprType.Desc=xtContext then begin
2745
// resolve aliases and properties
2747
Params.Flags:=fdfDefaultForExpressions;
2748
ExprType.Context:=ExprType.Context.Tool.FindBaseTypeOfNode(Params,
2749
ExprType.Context.Node);
2752
case ExprType.Desc of
2754
xtBoolean,xtByteBool,xtWordBool,xtLongBool,xtQWordBool:
2762
Node:=ExprType.Context.Node;
2763
Tool:=ExprType.Context.Tool;
2764
if Node=nil then exit;
2769
Node:=Node.FirstChild;
2770
while Node<>nil do begin
2771
List.Add(GetIdentifier(@Tool.Src[Node.StartPos]));
2772
Node:=Node.NextBrother;
2777
debugln(['TIdentCompletionTool.GetValuesOfCaseVariable not an enum: ',Node.DescAsString]);
2788
DeactivateGlobalWriteLock;
2792
procedure TIdentCompletionTool.CalcMemSize(Stats: TCTMemStats);
2795
Ext: TCodeTreeNodeExtension;
2798
inherited CalcMemSize(Stats);
2799
if FICTClassAndAncestors<>nil then
2800
Stats.Add('TIdentCompletionTool.ClassAndAncestors',
2801
FICTClassAndAncestors.Count*(SizeOf(TAVLTreeNode)+SizeOf(TCodeXYPosition)));
2802
if FIDCTFoundPublicProperties<>nil then
2803
Stats.Add('TIdentCompletionTool.FoundPublicProperties',
2804
FIDCTFoundPublicProperties.Count*SizeOf(TAVLTreeNode));
2805
if FIDTFoundMethods<>nil then begin
2806
m:=PtrUint(FIDTFoundMethods.Count)*SizeOf(TAVLTreeNode);
2807
Node:=FIDTFoundMethods.FindLowest;
2808
while Node<>nil do begin
2809
Ext:=TCodeTreeNodeExtension(Node.Data);
2810
inc(m,Ext.CalcMemSize);
2811
Node:=FIDTFoundMethods.FindSuccessor(Node);
2813
STats.Add('TIdentCompletionTool.FoundMethods',m);
2815
if CurrentIdentifierList<>nil then
2816
Stats.Add('TIdentCompletionTool.CurrentIdentifierList',
2817
CurrentIdentifierList.CalcMemSize);
2818
if CurrentIdentifierContexts<>nil then
2819
Stats.Add('TIdentCompletionTool.CurrentContexts',
2820
CurrentIdentifierContexts.CalcMemSize);
2823
{ TIdentifierListItem }
2825
function TIdentifierListItem.GetParamTypeList: string;
2827
ANode: TCodeTreeNode;
2829
if not (iliParamTypeListValid in Flags) then begin
2830
// Note: if you implement param lists for other than ctnProcedure, check
2833
if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin
2834
FParamTypeList:=Tool.ExtractProcHead(ANode,
2835
[phpWithoutClassKeyword,phpWithoutClassName,
2836
phpWithoutName,phpInUpperCase]);
2837
//debugln('TIdentifierListItem.GetParamTypeList A ',GetIdentifier(Identifier),' ',Tool.MainFilename,' ',dbgs(CurNode.StartPos));
2840
Include(Flags,iliParamTypeListValid);
2842
Result:=FParamTypeList;
2845
function TIdentifierListItem.GetParamNameList: string;
2847
ANode: TCodeTreeNode;
2849
if not (iliParamNameListValid in Flags) then begin
2850
// Note: if you implement param lists for other than ctnProcedure, check
2853
if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin
2854
FParamNameList:=Tool.ExtractProcHead(ANode,
2855
[phpWithoutClassKeyword,phpWithoutClassName,
2856
phpWithoutName,phpInUpperCase,phpWithParameterNames]);
2857
//debugln('TIdentifierListItem.GetParamNameList A ',GetIdentifier(Identifier),' ',Tool.MainFilename,' ',dbgs(CurNode.StartPos));
2860
Include(Flags,iliParamNameListValid);
2862
Result:=FParamNameList;
2865
function TIdentifierListItem.GetNode: TCodeTreeNode;
2871
if (iliNodeValid in Flags)
2872
and (FToolNodesDeletedStep<>Tool.NodesDeletedChangeStep) then
2873
Exclude(Flags,iliNodeValid);
2875
if (not (iliNodeValid in Flags)) then begin
2876
if iliNodeHashValid in Flags then begin
2878
if (iliNodeValid in Flags) then begin
2883
if FToolNodesDeletedStep=Tool.NodesDeletedChangeStep then begin
2886
if not (iliNodeGoneWarned in Flags) then begin
2887
DebugLn(['TIdentifierListItem.GetNode node ',Identifier,' is gone from ',Tool.MainFilename]);
2888
Include(Flags,iliNodeGoneWarned);
2895
procedure TIdentifierListItem.SetNode(const AValue: TCodeTreeNode);
2897
procedure RaiseToolMissing;
2899
raise Exception.Create('TIdentifierListItem.SetNode Node without Tool');
2904
Include(Flags,iliNodeValid);
2905
Exclude(Flags,iliNodeHashValid);
2906
if (FNode<>nil) and (Tool=nil) then
2909
FToolNodesDeletedStep:=Tool.NodesDeletedChangeStep;
2912
procedure TIdentifierListItem.SetParamTypeList(const AValue: string);
2914
FParamTypeList:=AValue;
2915
Include(Flags,iliParamTypeListValid);
2918
procedure TIdentifierListItem.SetParamNameList(const AValue: string);
2920
FParamNameList:=AValue;
2921
Include(Flags,iliParamNameListValid);
2924
procedure TIdentifierListItem.SetResultType(const AValue: string);
2926
FResultType := AValue;
2927
Include(Flags, iliResultTypeValid);
2930
function TIdentifierListItem.AsString: string;
2932
ANode: TCodeTreeNode;
2934
WriteStr(Result, Compatibility);
2936
Result:=Result+' HasChilds'
2938
Result:=Result+' HasNoChilds';
2939
Result:=Result+' History='+IntToStr(HistoryIndex);
2940
Result:=Result+' Ident='+Identifier;
2941
Result:=Result+' Lvl='+IntToStr(Level);
2943
Result:=Result+' File='+Tool.MainFilename;
2946
Result:=Result+' Node='+ANode.DescAsString
2947
+' "'+StringToPascalConst(copy(Tool.Src,ANode.StartPos,50))+'"';
2950
function TIdentifierListItem.GetDesc: TCodeTreeNodeDesc;
2952
ANode: TCodeTreeNode;
2958
Result:=DefaultDesc;
2961
constructor TIdentifierListItem.Create(
2962
NewCompatibility: TIdentifierCompatibility; NewHasChilds: boolean;
2963
NewHistoryIndex: integer; NewIdentifier: PChar; NewLevel: integer;
2964
NewNode: TCodeTreeNode; NewTool: TFindDeclarationTool;
2965
NewDefaultDesc: TCodeTreeNodeDesc);
2967
Compatibility:=NewCompatibility;
2968
if NewHasChilds then Include(FLags,iliHasChilds);
2969
HistoryIndex:=NewHistoryIndex;
2970
Identifier:=GetIdentifier(NewIdentifier);
2974
DefaultDesc:=NewDefaultDesc;
2975
BaseExprType:=CleanExpressionType;
2978
function TIdentifierListItem.IsProcNodeWithParams: boolean;
2980
ANode: TCodeTreeNode;
2983
Result:=(GetDesc=ctnProcedure);
2984
if not Result then exit;
2985
if (iliParamNameListValid in Flags) then begin
2987
while (StartPos<=length(FParamTypeList))
2988
and (FParamTypeList[StartPos] in [' ',#9,'(','[']) do
2990
if (StartPos<=length(FParamTypeList))
2991
and (FParamTypeList[StartPos] in [')',']',';']) then
2995
end else if (iliParamTypeListValid in Flags) then begin
2996
// the type list does not contain names
2997
// so a () could be empty or (var buf)
2999
while (StartPos<=length(FParamTypeList))
3000
and (FParamTypeList[StartPos] in [' ',#9,'(','[']) do
3002
if (StartPos<=length(FParamTypeList))
3003
and (not (FParamTypeList[StartPos] in [')',']',';'])) then
3007
Result:=(ANode<>nil) and Tool.ProcNodeHasParamList(ANode);
3010
function TIdentifierListItem.IsPropertyWithParams: boolean;
3012
ANode: TCodeTreeNode;
3014
if not (iliHasParamListValid in Flags) then begin
3015
Include(Flags,iliHasParamListValid);
3017
if (ANode<>nil) and Tool.PropertyNodeHasParamList(ANode) then
3018
Include(Flags,iliHasParamList)
3020
Exclude(Flags,iliHasParamList);
3022
Result:=iliHasParamList in Flags;
3025
function TIdentifierListItem.IsPropertyReadOnly: boolean;
3027
ANode: TCodeTreeNode;
3029
if not (iliIsReadOnlyValid in Flags) then begin
3030
Include(Flags,iliIsReadOnlyValid);
3032
if (ANode<>nil) and Tool.PropertyHasSpecifier(ANode,'read',false)
3033
and not Tool.PropertyHasSpecifier(ANode,'write',false) then
3034
Include(Flags,iliIsReadOnly)
3036
Exclude(Flags,iliIsReadOnly);
3038
Result:=iliIsReadOnly in Flags;
3041
function TIdentifierListItem.GetHintModifiers: TPascalHintModifiers;
3043
ANode: TCodeTreeNode;
3046
if not (iliHintModifiersValid in Flags) then begin
3047
Include(Flags,iliHintModifiersValid);
3049
if ANode<>nil then begin
3050
Result:=Tool.GetHintModifiers(ANode);
3051
if phmDeprecated in Result then Include(Flags,iliIsDeprecated);
3052
if phmPlatform in Result then Include(Flags,iliIsPlatform);
3053
if phmLibrary in Result then Include(Flags,iliIsLibrary);
3054
if phmUnimplemented in Result then Include(Flags,iliIsUnimplemented);
3055
if phmExperimental in Result then Include(Flags,iliIsExperimental);
3058
if iliIsDeprecated in Flags then Include(Result,phmDeprecated);
3059
if iliIsPlatform in Flags then Include(Result,phmPlatform);
3060
if iliIsLibrary in Flags then Include(Result,phmLibrary);
3061
if iliIsUnimplemented in Flags then Include(Result,phmUnimplemented);
3062
if iliIsExperimental in Flags then Include(Result,phmExperimental);
3066
function TIdentifierListItem.CheckHasChilds: boolean;
3067
// returns true if test was successful
3069
ANode: TCodeTreeNode;
3072
if GetDesc in AllClasses then begin
3077
if ANode=nil then exit;
3079
if (BaseExprType.Desc=xtContext)
3080
and (BaseExprType.Context.Node<>nil)
3081
and (BaseExprType.Context.Node.Desc in AllClasses)
3083
Include(Flags,iliHasChilds);
3087
function TIdentifierListItem.CanBeAssigned: boolean;
3089
ANode: TCodeTreeNode;
3093
if (ANode=nil) then exit;
3094
if (GetDesc=ctnVarDefinition) then
3096
if (ANode.Desc in [ctnProperty,ctnGlobalProperty]) then begin
3097
if Tool.PropertyHasSpecifier(ANode,'write') then exit(true);
3098
if Tool.PropNodeIsTypeLess(ANode) then begin
3099
exit(true);// ToDo: search the real property definition
3104
procedure TIdentifierListItem.UpdateBaseContext;
3106
Params: TFindDeclarationParams;
3107
ANode: TCodeTreeNode;
3109
if (iliBaseExprTypeValid in Flags) then exit;
3110
Include(Flags,iliBaseExprTypeValid);
3111
BaseExprType:=CleanExpressionType;
3112
BaseExprType.Desc:=xtNone;
3114
if (ANode<>nil) and (Tool<>nil) then begin
3115
Tool.ActivateGlobalWriteLock;
3116
Params:=TFindDeclarationParams.Create;
3118
if ANode.HasParentOfType(ctnGenericType) then exit;
3119
BaseExprType.Context:=Tool.FindBaseTypeOfNode(Params,ANode);
3120
if (BaseExprType.Context.Node<>nil) then
3121
BaseExprType.Desc:=xtContext;
3124
Tool.DeactivateGlobalWriteLock;
3129
function TIdentifierListItem.HasChilds: boolean;
3131
Result:=iliHasChilds in Flags;
3134
function TIdentifierListItem.HasIndex: boolean;
3135
// check if edged bracket can be used []
3137
ANode: TCodeTreeNode;
3139
if not (iliHasIndexValid in Flags) then begin
3141
if BaseExprType.Desc in (xtAllStringConvertibles+xtAllWideStringConvertibles)
3143
// strings, widestrings and PChar
3144
Include(Flags,iliHasIndex);
3145
end else if (BaseExprType.Desc=xtContext) and (BaseExprType.Context.Node<>nil)
3147
//debugln(['TIdentifierListItem.HasIndex ',BaseExprType.Context.Node.DescAsString]);
3148
ANode:=BaseExprType.Context.Node;
3150
ctnRangedArrayType,ctnOpenArrayType: Include(Flags,iliHasIndex);
3154
Result:=iliHasIndex in Flags;
3157
function TIdentifierListItem.IsFunction: boolean;
3159
ANode: TCodeTreeNode;
3161
if not (iliIsFunctionValid in Flags) then
3164
if (ANode <> nil) and Tool.NodeIsFunction(ANode) then
3165
Include(Flags, iliIsFunction);
3166
Include(Flags, iliIsFunctionValid);
3168
Result := iliIsFunction in Flags;
3171
function TIdentifierListItem.IsContructor: boolean;
3173
ANode: TCodeTreeNode;
3175
if not (iliIsConstructorValid in Flags) then
3178
if (ANode <> nil) and Tool.NodeIsConstructor(ANode) then
3179
Include(Flags, iliIsConstructor);
3180
Include(Flags, iliIsConstructorValid);
3182
Result := iliIsConstructor in Flags;
3185
function TIdentifierListItem.IsDestructor: boolean;
3187
ANode: TCodeTreeNode;
3189
if not (iliIsDestructorValid in Flags) then
3192
if (ANode <> nil) and Tool.NodeIsDestructor(ANode) then
3193
Include(Flags, iliIsDestructor);
3194
Include(Flags, iliIsDestructorValid);
3196
Result := iliIsDestructor in Flags;
3199
function TIdentifierListItem.IsAbstractMethod: boolean;
3201
ANode: TCodeTreeNode;
3203
if not (iliIsAbstractMethodValid in Flags) then begin
3206
and Tool.ProcNodeHasSpecifier(ANode,psABSTRACT) then
3207
Include(Flags,iliIsAbstractMethod);
3208
Include(Flags,iliIsAbstractMethodValid);
3210
Result:=iliIsAbstractMethod in Flags;
3213
function TIdentifierListItem.TryIsAbstractMethod: boolean;
3216
Result:=IsAbstractMethod;
3222
procedure TIdentifierListItem.Clear;
3226
Compatibility:=icompUnknown;
3232
DefaultDesc:=ctnNone;
3234
BaseExprType:=CleanExpressionType;
3237
procedure TIdentifierListItem.UnbindNode;
3239
if FNode=nil then exit;
3241
Exclude(Flags,iliNodeValid);
3245
procedure TIdentifierListItem.StoreNodeHash;
3247
Include(Flags,iliNodeHashValid);
3248
FNodeStartPos:=FNode.StartPos;
3249
FNodeDesc:=FNode.Desc;
3250
FNodeHash:=GetNodeHash(FNode);
3251
//DebugLn(['TIdentifierListItem.StoreNodeHash ',Identifier,' Pos=',FNodeStartPos,' Hash=',FNodeHash]);
3254
function TIdentifierListItem.RestoreNode: boolean;
3256
NewNode: TCodeTreeNode;
3259
if not (iliNodeHashValid in Flags) then exit(true);
3260
//DebugLn(['TIdentifierListItem.RestoreNode ',Identifier]);
3261
NewNode:=Tool.BuildSubTreeAndFindDeepestNodeAtPos(FNodeStartPos,false);
3263
if (NewNode=nil) or (NewNode.StartPos<>FNodeStartPos)
3264
or (NewNode.Desc<>FNodeDesc) then begin
3265
DebugLn(['TIdentifierListItem.RestoreNode not found: ',Identifier]);
3266
Exclude(Flags,iliNodeHashValid);
3269
NewHash:=GetNodeHash(NewNode);
3270
if NewHash<>FNodeHash then begin
3271
DebugLn(['TIdentifierListItem.RestoreNode hash changed: ',Identifier]);
3272
Exclude(Flags,iliNodeHashValid);
3275
//DebugLn(['TIdentifierListItem.RestoreNode Success ',Identifier]);
3280
function TIdentifierListItem.GetNodeHash(ANode: TCodeTreeNode): string;
3286
ctnVarDefinition,ctnConstDefinition,ctnTypeDefinition,ctnGenericType:
3287
Result:=Tool.ExtractDefinitionName(ANode)
3289
StartPos:=ANode.StartPos;
3290
EndPos:=StartPos+20;
3291
if EndPos>ANode.EndPos then EndPos:=ANode.EndPos;
3292
Result:=copy(Tool.Src,StartPos,EndPos);
3296
function TIdentifierListItem.CompareParamList(CompareItem: TIdentifierListItem
3299
ANode: TCodeTreeNode;
3300
CmpNode: TCodeTreeNode;
3303
if Self=CompareItem then exit;
3305
CmpNode:=CompareItem.Node;
3306
if (ANode=CmpNode) then exit;
3307
if (ANode=nil) or (CmpNode=nil) then exit;
3308
if (ANode.Desc<>ctnProcedure) or (CmpNode.Desc<>ctnProcedure) then
3310
{DbgOut('TIdentifierListItem.CompareParamList ',GetIdentifier(Identifier),'=',GetIdentifier(CompareItem.Identifier));
3312
DbgOut(' Self=',Tool.MainFilename,' ',dbgs(Node.StartPos));
3313
if CompareItem.Node<>nil then
3314
DbgOut(' Other=',CompareItem.Tool.MainFilename,' ',dbgs(CompareItem.Node.StartPos));
3316
Result:=CompareTextIgnoringSpace(ParamTypeList,CompareItem.ParamTypeList,false);
3319
function TIdentifierListItem.CompareParamList(
3320
CompareItem: TIdentifierListSearchItem): integer;
3322
if (ParamTypeList='') and (CompareItem.ParamList='') then
3324
Result:=CompareTextIgnoringSpace(ParamTypeList,CompareItem.ParamList,false);
3327
function TIdentifierListItem.CalcMemSize: PtrUInt;
3329
Result:=PtrUInt(InstanceSize)
3330
+MemSizeString(FParamTypeList)
3331
+MemSizeString(FNodeHash)
3332
+MemSizeString(Identifier);
3335
{ TIdentifierHistoryList }
3337
procedure TIdentifierHistoryList.SetCapacity(const AValue: integer);
3339
if FCapacity=AValue then exit;
3341
if FCapacity<1 then FCapacity:=1;
3342
while (FItems.Count>0) and (FItems.Count>=FCapacity) do
3343
FItems.FreeAndDelete(FItems.FindHighest);
3346
function TIdentifierHistoryList.FindItem(NewItem: TIdentifierListItem
3349
if NewItem<>nil then
3350
Result:=FItems.FindKey(NewItem,@CompareIdentItemWithHistListItem)
3355
constructor TIdentifierHistoryList.Create;
3357
FItems:=TAVLTree.Create(@CompareIdentHistListItem);
3361
destructor TIdentifierHistoryList.Destroy;
3368
procedure TIdentifierHistoryList.Clear;
3370
FItems.FreeAndClear;
3373
procedure TIdentifierHistoryList.Add(NewItem: TIdentifierListItem);
3375
OldAVLNode: TAVLTreeNode;
3376
NewHistItem: TIdentHistListItem;
3377
AnAVLNode: TAVLTreeNode;
3378
AdjustIndex: Integer;
3379
AnHistItem: TIdentHistListItem;
3381
if NewItem=nil then exit;
3382
OldAVLNode:=FindItem(NewItem);
3383
{$IFDEF ShowHistory}
3384
DebugLn('TIdentifierHistoryList.Add Count=',Count,' Found=',OldAVLNode<>nil,
3385
' ITEM: ',NewItem.AsString);
3387
if OldAVLNode<>nil then begin
3389
NewHistItem:=TIdentHistListItem(OldAVLNode.Data);
3390
if NewHistItem.HistoryIndex=0 then exit;
3391
// must be moved -> remove it from the tree
3392
AdjustIndex:=NewHistItem.HistoryIndex;
3393
FItems.Delete(OldAVLNode);
3395
// create a new history item
3396
NewHistItem:=TIdentHistListItem.Create;
3397
NewHistItem.Identifier:=NewItem.Identifier;
3398
NewHistItem.NodeDesc:=NewItem.GetDesc;
3399
NewHistItem.ParamList:=NewItem.ParamTypeList;
3402
NewHistItem.HistoryIndex:=0;
3403
// adjust all other HistoryIndex
3404
AnAVLNode:=Fitems.FindLowest;
3405
while AnAVLNode<>nil do begin
3406
AnHistItem:=TIdentHistListItem(AnAVLNode.Data);
3407
if AnHistItem.HistoryIndex>=AdjustIndex then
3408
inc(AnHistItem.HistoryIndex);
3409
AnAVLNode:=FItems.FindSuccessor(AnAVLNode);
3411
if (FItems.Count>0) and (FItems.Count>=FCapacity) then
3412
FItems.FreeAndDelete(FItems.FindHighest);
3413
FItems.Add(NewHistItem);
3414
{$IFDEF ShowHistory}
3415
DebugLn('TIdentifierHistoryList.Added Count=',Count);
3419
function TIdentifierHistoryList.GetHistoryIndex(AnItem: TIdentifierListItem
3422
AnAVLNode: TAVLTreeNode;
3424
AnAVLNode:=FindItem(AnItem);
3425
if AnAVLNode=nil then
3426
Result:=33333333 // a very high value
3428
Result:=TIdentHistListItem(AnAVLNode.Data).HistoryIndex;
3431
function TIdentifierHistoryList.Count: integer;
3433
Result:=FItems.Count;
3436
function TIdentifierHistoryList.CalcMemSize: PtrUInt;
3439
Item: TIdentHistListItem;
3441
Result:=PtrUInt(InstanceSize);
3442
if FItems<>nil then begin
3443
inc(Result,FItems.Count*SizeOf(TAVLTreeNode));
3444
Node:=FItems.FindLowest;
3445
while Node<>nil do begin
3446
Item:=TIdentHistListItem(Node.Data);
3447
inc(Result,Item.CalcMemSize);
3448
Node:=FItems.FindSuccessor(Node);
3453
{ TCodeContextInfo }
3455
function TCodeContextInfo.GetItems(Index: integer): TCodeContextInfoItem;
3457
Result:=TCodeContextInfoItem(FItems[Index]);
3460
constructor TCodeContextInfo.Create;
3462
FItems:=TFPList.Create;
3465
destructor TCodeContextInfo.Destroy;
3472
function TCodeContextInfo.Count: integer;
3474
Result:=FItems.Count;
3477
function TCodeContextInfo.Add(const Context: TExpressionType): integer;
3479
Item: TCodeContextInfoItem;
3481
Item:=TCodeContextInfoItem.Create;
3483
Result:=FItems.Add(Item);
3486
function TCodeContextInfo.AddCompilerProc: integer;
3488
Item: TCodeContextInfoItem;
3490
Item:=TCodeContextInfoItem.Create;
3491
Result:=FItems.Add(Item);
3494
procedure TCodeContextInfo.Clear;
3498
for i:=0 to FItems.Count-1 do
3499
TObject(FItems[i]).Free;
3503
function TCodeContextInfo.CalcMemSize: PtrUInt;
3505
Result:=PtrUInt(InstanceSize)
3506
+PtrUInt(TCodeContextInfoItem)*SizeOf(FItems.Count)
3507
+MemSizeString(FProcName);
3510
{ TIdentifierListSearchItem }
3512
function TIdentifierListSearchItem.CalcMemSize: PtrUInt;
3514
Result:=PtrUInt(InstanceSize)
3515
+MemSizeString(ParamList);
3518
{ TIdentHistListItem }
3520
function TIdentHistListItem.CalcMemSize: PtrUInt;
3522
Result:=PtrUInt(InstanceSize)
3523
+MemSizeString(Identifier)
3524
+MemSizeString(ParamList);
3527
{ TCodeContextInfoItem }
3529
destructor TCodeContextInfoItem.Destroy;