MG: added global write lock

git-svn-id: trunk@647 -
This commit is contained in:
lazarus 2002-01-30 15:40:48 +00:00
parent 74e824eddf
commit 6f4f1d0688
6 changed files with 161 additions and 70 deletions

View File

@ -71,6 +71,8 @@ type
FSourceTools: TAVLTree; // tree of TCustomCodeTool FSourceTools: TAVLTree; // tree of TCustomCodeTool
FVisibleEditorLines: integer; FVisibleEditorLines: integer;
FWriteExceptions: boolean; FWriteExceptions: boolean;
FWriteLockCount: integer;// Set/Unset counter
FWriteLockStep: integer; // current write lock ID
function OnScannerGetInitValues(Code: Pointer): TExpressionEvaluator; function OnScannerGetInitValues(Code: Pointer): TExpressionEvaluator;
procedure OnDefineTreeReadValue(Sender: TObject; const VariableName: string; procedure OnDefineTreeReadValue(Sender: TObject; const VariableName: string;
var Value: string); var Value: string);
@ -90,6 +92,11 @@ type
function HandleException(AnException: Exception): boolean; function HandleException(AnException: Exception): boolean;
function OnGetCodeToolForBuffer(Sender: TObject; function OnGetCodeToolForBuffer(Sender: TObject;
Code: TCodeBuffer): TFindDeclarationTool; Code: TCodeBuffer): TFindDeclarationTool;
procedure ActivateWriteLock;
procedure DeactivateWriteLock;
procedure OnToolSetWriteLock(Lock: boolean);
procedure OnToolGetWriteLockInfo(var WriteLockIsSet: boolean;
var WriteLockStep: integer);
public public
DefinePool: TDefinePool; // definition templates (rules) DefinePool: TDefinePool; // definition templates (rules)
DefineTree: TDefineTree; // cache for defines (e.g. initial compiler values) DefineTree: TDefineTree; // cache for defines (e.g. initial compiler values)
@ -433,6 +440,8 @@ begin
// create a scanner for the unit/program // create a scanner for the unit/program
Result.Scanner:=TLinkScanner.Create; Result.Scanner:=TLinkScanner.Create;
Result.Scanner.OnGetInitValues:=@OnScannerGetInitValues; Result.Scanner.OnGetInitValues:=@OnScannerGetInitValues;
Result.Scanner.OnSetGlobalWriteLock:=@OnToolSetWriteLock;
Result.Scanner.OnGetGlobalWriteLockInfo:=@OnToolGetWriteLockInfo;
end; end;
end; end;
@ -1360,6 +1369,35 @@ writeln('[TCodeToolManager.OnGetCodeToolForBuffer]'
Result:=TFindDeclarationTool(GetCodeToolForSource(Code,true)); Result:=TFindDeclarationTool(GetCodeToolForSource(Code,true));
end; end;
procedure TCodeToolManager.ActivateWriteLock;
begin
if FWriteLockCount=0 then begin
// start a new write lock
if FWriteLockStep<>$7fffffff then
inc(FWriteLockStep)
else
FWriteLockStep:=-$7fffffff;
end;
inc(FWriteLockCount);
end;
procedure TCodeToolManager.DeactivateWriteLock;
begin
if FWriteLockCount>0 then dec(FWriteLockCount);
end;
procedure TCodeToolManager.OnToolGetWriteLockInfo(var WriteLockIsSet: boolean;
var WriteLockStep: integer);
begin
WriteLockIsSet:=FWriteLockCount>0;
WriteLockStep:=FWriteLockStep;
end;
procedure TCodeToolManager.OnToolSetWriteLock(Lock: boolean);
begin
if Lock then ActivateWriteLock else DeactivateWriteLock;
end;
function TCodeToolManager.ConsistencyCheck: integer; function TCodeToolManager.ConsistencyCheck: integer;
// 0 = ok // 0 = ok
begin begin

View File

@ -1377,7 +1377,7 @@ end;
function TCustomCodeTool.UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean; function TCustomCodeTool.UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean;
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('TCustomCodeTool.UpdateNeeded A ',Scanner<>nil); writeln('TCustomCodeTool.UpdateNeeded A ',Scanner<>nil,' FForceUpdateNeeded=',FForceUpdateNeeded);
{$ENDIF} {$ENDIF}
if FForceUpdateNeeded then begin if FForceUpdateNeeded then begin
Result:=true; Result:=true;
@ -1387,7 +1387,7 @@ writeln('TCustomCodeTool.UpdateNeeded A ',Scanner<>nil);
or (Scanner.UpdateNeeded(OnlyInterfaceNeeded, CheckFilesOnDisk)); or (Scanner.UpdateNeeded(OnlyInterfaceNeeded, CheckFilesOnDisk));
FForceUpdateNeeded:=Result; FForceUpdateNeeded:=Result;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('TCustomCodeTool.UpdateNeeded END'); writeln('TCustomCodeTool.UpdateNeeded END Result=',Result);
{$ENDIF} {$ENDIF}
end; end;
@ -1475,7 +1475,6 @@ begin
Tree.Clear; Tree.Clear;
end; end;
{ ECodeToolError } { ECodeToolError }
constructor ECodeToolError.Create(ASender: TCustomCodeTool; constructor ECodeToolError.Create(ASender: TCustomCodeTool;

View File

@ -293,9 +293,9 @@ type
TFindDeclarationTool = class(TPascalParserTool) TFindDeclarationTool = class(TPascalParserTool)
private private
FOnGetUnitSourceSearchPath: TOnGetSearchPath;
FOnGetCodeToolForBuffer: TOnGetCodeToolForBuffer;
FInterfaceIdentifierCache: TInterfaceIdentifierCache; FInterfaceIdentifierCache: TInterfaceIdentifierCache;
FOnGetCodeToolForBuffer: TOnGetCodeToolForBuffer;
FOnGetUnitSourceSearchPath: TOnGetSearchPath;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugPrefix: string; DebugPrefix: string;
procedure IncPrefix; procedure IncPrefix;
@ -388,10 +388,10 @@ type
AnUnitInFilename: string): TCodeBuffer; AnUnitInFilename: string): TCodeBuffer;
property InterfaceIdentifierCache: TInterfaceIdentifierCache property InterfaceIdentifierCache: TInterfaceIdentifierCache
read FInterfaceIdentifierCache; read FInterfaceIdentifierCache;
property OnGetUnitSourceSearchPath: TOnGetSearchPath
read FOnGetUnitSourceSearchPath write FOnGetUnitSourceSearchPath;
property OnGetCodeToolForBuffer: TOnGetCodeToolForBuffer property OnGetCodeToolForBuffer: TOnGetCodeToolForBuffer
read FOnGetCodeToolForBuffer write FOnGetCodeToolForBuffer; read FOnGetCodeToolForBuffer write FOnGetCodeToolForBuffer;
property OnGetUnitSourceSearchPath: TOnGetSearchPath
read FOnGetUnitSourceSearchPath write FOnGetUnitSourceSearchPath;
end; end;
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -563,76 +563,81 @@ var CleanCursorPos: integer;
Params: TFindDeclarationParams; Params: TFindDeclarationParams;
begin begin
Result:=false; Result:=false;
// build code tree Scanner.ActivateGlobalWriteLock;
try
// build code tree
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y); writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y);
{$ENDIF} {$ENDIF}
BuildTreeAndGetCleanPos(false,CursorPos,CleanCursorPos); BuildTreeAndGetCleanPos(false,CursorPos,CleanCursorPos);
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos); writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos);
{$ENDIF} {$ENDIF}
// find CodeTreeNode at cursor // find CodeTreeNode at cursor
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
if IsIncludeDirectiveAtPos(CleanCursorPos,CursorNode.StartPos,NewPos.Code) if IsIncludeDirectiveAtPos(CleanCursorPos,CursorNode.StartPos,NewPos.Code)
then begin then begin
NewPos.X:=1; NewPos.X:=1;
NewPos.Y:=1; NewPos.Y:=1;
NewTopLine:=1; NewTopLine:=1;
Result:=true; Result:=true;
exit; exit;
end; end;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc)); writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc));
{$ENDIF} {$ENDIF}
if CursorNode.Desc=ctnUsesSection then begin if CursorNode.Desc=ctnUsesSection then begin
// find used unit // find used unit
Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos, Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos,
NewPos,NewTopLine); NewPos,NewTopLine);
end else begin end else begin
// first test if in a class // first test if in a class
ClassNode:=CursorNode; ClassNode:=CursorNode;
while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do
ClassNode:=ClassNode.Parent; ClassNode:=ClassNode.Parent;
if ClassNode<>nil then begin if ClassNode<>nil then begin
// cursor is in class/object definition // cursor is in class/object definition
if (ClassNode.SubDesc and ctnsForwardDeclaration)=0 then begin if (ClassNode.SubDesc and ctnsForwardDeclaration)=0 then begin
// parse class and build CodeTreeNodes for all properties/methods // parse class and build CodeTreeNodes for all properties/methods
BuildSubTreeForClass(ClassNode); BuildSubTreeForClass(ClassNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
end;
end;
if CursorNode.Desc=ctnBeginBlock then begin
BuildSubTreeForBeginBlock(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
end; end;
end; MoveCursorToCleanPos(CleanCursorPos);
if CursorNode.Desc=ctnBeginBlock then begin while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do
BuildSubTreeForBeginBlock(CursorNode); dec(CurPos.StartPos);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); if (CurPos.StartPos>=1) and (IsIdentStartChar[Src[CurPos.StartPos]]) then
end; begin
MoveCursorToCleanPos(CleanCursorPos); CurPos.EndPos:=CurPos.StartPos;
while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do while (CurPos.EndPos<=SrcLen) and IsIdentChar[Src[CurPos.EndPos]] do
dec(CurPos.StartPos); inc(CurPos.EndPos);
if (CurPos.StartPos>=1) and (IsIdentStartChar[Src[CurPos.StartPos]]) then // find declaration of identifier
begin Params:=TFindDeclarationParams.Create;
CurPos.EndPos:=CurPos.StartPos; try
while (CurPos.EndPos<=SrcLen) and IsIdentChar[Src[CurPos.EndPos]] do Params.ContextNode:=CursorNode;
inc(CurPos.EndPos); Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier);
// find declaration of identifier Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes,
Params:=TFindDeclarationParams.Create; fdfExceptionOnNotFound];
try Result:=FindDeclarationOfIdentifier(Params);
Params.ContextNode:=CursorNode; if Result then begin
Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier); Params.ConvertResultCleanPosToCaretPos;
Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes, NewPos:=Params.NewPos;
fdfExceptionOnNotFound]; NewTopLine:=Params.NewTopLine;
Result:=FindDeclarationOfIdentifier(Params); end;
if Result then begin finally
Params.ConvertResultCleanPosToCaretPos; Params.Free;
NewPos:=Params.NewPos;
NewTopLine:=Params.NewTopLine;
end; end;
finally end else begin
Params.Free; // find declaration of not identifier
end; end;
end else begin
// find declaration of not identifier
end; end;
finally
Scanner.DeactivateGlobalWriteLock;
end; end;
end; end;
@ -3851,7 +3856,8 @@ begin
while IsIdentChar[Identifier[Len]] do inc(Len); while IsIdentChar[Identifier[Len]] do inc(Len);
GetMem(Result,Len+1); GetMem(Result,Len+1);
Move(Identifier^,Result^,Len+1); Move(Identifier^,Result^,Len+1);
if FItems=nil then FItems:=TAVLTree.Create(@CompareIdentifiers); if FItems=nil then
FItems:=TAVLTree.Create(TListSortCompare(@CompareIdentifiers));
FItems.Add(Result); FItems.Add(Result);
end; end;

View File

@ -59,6 +59,10 @@ type
TOnCheckFileOnDisk = function(Code: Pointer): boolean of object; TOnCheckFileOnDisk = function(Code: Pointer): boolean of object;
TOnGetInitValues = function(Code: Pointer): TExpressionEvaluator of object; TOnGetInitValues = function(Code: Pointer): TExpressionEvaluator of object;
TOnIncludeCode = procedure(ParentCode, IncludeCode: Pointer) of object; TOnIncludeCode = procedure(ParentCode, IncludeCode: Pointer) of object;
TOnSetWriteLock = procedure(Lock: boolean) of object;
TOnGetWriteLockInfo = procedure(var WriteLockIsSet: boolean;
var WriteLockStep: integer) of object;
TSourceLink = record TSourceLink = record
CleanedPos: integer; CleanedPos: integer;
@ -98,6 +102,9 @@ type
FIgnoreMissingIncludeFiles: boolean; FIgnoreMissingIncludeFiles: boolean;
FNestedComments: boolean; FNestedComments: boolean;
FForceUpdateNeeded: boolean; FForceUpdateNeeded: boolean;
FLastGlobalWriteLockStep: integer;
FOnGetGlobalWriteLockInfo: TOnGetWriteLockInfo;
FOnSetGlobalWriteLock: TOnSetWriteLock;
function GetLinks(Index: integer): TSourceLink; function GetLinks(Index: integer): TSourceLink;
procedure SetLinks(Index: integer; const Value: TSourceLink); procedure SetLinks(Index: integer; const Value: TSourceLink);
procedure SetSource(ACode: Pointer); // set current source procedure SetSource(ACode: Pointer); // set current source
@ -215,9 +222,17 @@ type
property ScanTillInterfaceEnd: boolean property ScanTillInterfaceEnd: boolean
read FScanTillInterfaceEnd write SetScanTillInterfaceEnd; read FScanTillInterfaceEnd write SetScanTillInterfaceEnd;
procedure Scan(TillInterfaceEnd, CheckFilesOnDisk: boolean); procedure Scan(TillInterfaceEnd, CheckFilesOnDisk: boolean);
function UpdateNeeded(OnlyInterfaceNeeded, function UpdateNeeded(OnlyInterfaceNeeded,
CheckFilesOnDisk: boolean): boolean; CheckFilesOnDisk: boolean): boolean;
property ChangeStep: integer read FChangeStep; property ChangeStep: integer read FChangeStep;
procedure ActivateGlobalWriteLock;
procedure DeactivateGlobalWriteLock;
property OnGetGlobalWriteLockInfo: TOnGetWriteLockInfo
read FOnGetGlobalWriteLockInfo write FOnGetGlobalWriteLockInfo;
property OnSetGlobalWriteLock: TOnSetWriteLock
read FOnSetGlobalWriteLock write FOnSetGlobalWriteLock;
procedure Clear; procedure Clear;
function ConsistencyCheck: integer; function ConsistencyCheck: integer;
procedure WriteDebugReport; procedure WriteDebugReport;
@ -851,9 +866,29 @@ function TLinkScanner.UpdateNeeded(
var i: integer; var i: integer;
SrcLog: TSourceLog; SrcLog: TSourceLog;
NewInitValues: TExpressionEvaluator; NewInitValues: TExpressionEvaluator;
GlobalWriteLockIsSet: boolean;
GlobalWriteLockStep: integer;
begin begin
Result:=true; Result:=true;
if FForceUpdateNeeded then exit; if FForceUpdateNeeded then exit;
if Assigned(OnGetGlobalWriteLockInfo) then begin
OnGetGlobalWriteLockInfo(GlobalWriteLockIsSet,GlobalWriteLockStep);
if GlobalWriteLockIsSet then begin
// The global write lock is set. That means, input variables and code are
// frozen
if (FLastGlobalWriteLockStep=GlobalWriteLockStep) then begin
// source and values did not change since last UpdateNeeded check
// -> check only if ScanRange has increased
if (OnlyInterfaceNeeded=false) and (not EndOfSourceFound) then exit;
Result:=false;
exit;
end else begin
// this is the first check in this GlobalWriteLockStep
FLastGlobalWriteLockStep:=GlobalWriteLockStep;
// proceed normally ...
end;
end;
end;
FForceUpdateNeeded:=true; FForceUpdateNeeded:=true;
//writeln('TLinkScanner.UpdateNeeded A OnlyInterface=',OnlyInterfaceNeeded,' EndOfSourceFound=',EndOfSourceFound); //writeln('TLinkScanner.UpdateNeeded A OnlyInterface=',OnlyInterfaceNeeded,' EndOfSourceFound=',EndOfSourceFound);
if LinkCount=0 then exit; if LinkCount=0 then exit;
@ -1629,6 +1664,16 @@ begin
end; end;
end; end;
procedure TLinkScanner.ActivateGlobalWriteLock;
begin
if Assigned(OnSetGlobalWriteLock) then OnSetGlobalWriteLock(true);
end;
procedure TLinkScanner.DeactivateGlobalWriteLock;
begin
if Assigned(OnSetGlobalWriteLock) then OnSetGlobalWriteLock(false);
end;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
procedure InternalInit; procedure InternalInit;

View File

@ -214,6 +214,7 @@ type
function NodeHasParentOfType(ANode: TCodeTreeNode; function NodeHasParentOfType(ANode: TCodeTreeNode;
NodeDesc: TCodeTreeNodeDesc): boolean; NodeDesc: TCodeTreeNodeDesc): boolean;
function PropertyIsDefault(PropertyNode: TCodeTreeNode): boolean; function PropertyIsDefault(PropertyNode: TCodeTreeNode): boolean;
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
end; end;
@ -467,15 +468,15 @@ end;
procedure TPascalParserTool.BuildTree(OnlyInterfaceNeeded: boolean); procedure TPascalParserTool.BuildTree(OnlyInterfaceNeeded: boolean);
begin begin
writeln('TPascalParserTool.BuildTree A OnlyInterfaceNeeded=',OnlyInterfaceNeeded,
' ',TCodeBuffer(Scanner.MainCode).Filename);
{$IFDEF MEM_CHECK} {$IFDEF MEM_CHECK}
CheckHeap('TBasicCodeTool.BuildTree A '+IntToStr(GetMem_Cnt)); CheckHeap('TBasicCodeTool.BuildTree A '+IntToStr(GetMem_Cnt));
{$ENDIF} {$ENDIF}
if not UpdateNeeded(OnlyInterfaceNeeded) then exit;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('TPascalParserTool.BuildTree B'); writeln('TPascalParserTool.BuildTree A');
{$ENDIF} {$ENDIF}
if not UpdateNeeded(OnlyInterfaceNeeded) then exit;
writeln('TPascalParserTool.BuildTree B OnlyInterfaceNeeded=',OnlyInterfaceNeeded,
' ',TCodeBuffer(Scanner.MainCode).Filename);
//CheckHeap('TBasicCodeTool.BuildTree B '+IntToStr(GetMem_Cnt)); //CheckHeap('TBasicCodeTool.BuildTree B '+IntToStr(GetMem_Cnt));
BeginParsing(true,OnlyInterfaceNeeded); BeginParsing(true,OnlyInterfaceNeeded);
InterfaceSectionFound:=false; InterfaceSectionFound:=false;

View File

@ -659,8 +659,10 @@ end;
procedure TSourceLog.IncreaseChangeStep; procedure TSourceLog.IncreaseChangeStep;
begin begin
if FChangeStep=$7fffffff then FChangeStep:=-$7fffffff if FChangeStep<>$7fffffff then
else inc(FChangeStep); inc(FChangeStep)
else
FChangeStep:=-$7fffffff;
//writeln('[TSourceLog.IncreaseChangeStep] ',FChangeStep,',',HexStr(Cardinal(Self),8)); //writeln('[TSourceLog.IncreaseChangeStep] ',FChangeStep,',',HexStr(Cardinal(Self),8));
end; end;