codetools: cache for parsing ppu files

git-svn-id: trunk@29455 -
This commit is contained in:
mattias 2011-02-10 21:56:58 +00:00
parent a32a5f13a0
commit da98b47570
6 changed files with 263 additions and 46 deletions

View File

@ -43,7 +43,8 @@ uses
Classes, SysUtils, FileProcs, BasicCodeTools, CodeToolsStrConsts, TypInfo,
EventCodeTool, CodeTree, CodeAtom, SourceChanger, DefineTemplates, CodeCache,
ExprEval, LinkScanner, KeywordFuncLists, FindOverloads, CodeBeautifier,
FindDeclarationCache, DirectoryCacher, AVL_Tree, LFMTrees, DirectivesTree,
FindDeclarationCache, DirectoryCacher, AVL_Tree,
PPUCodeTools, LFMTrees, DirectivesTree,
PascalParserTool, CodeToolsConfig, CustomCodeTool, FindDeclarationTool,
IdentCompletionTool, StdCodeTools, ResourceCodeTool, CodeToolsStructs,
CodeTemplatesTool, ExtractProcTool;
@ -167,6 +168,7 @@ type
DefineTree: TDefineTree; // cache for defines (e.g. initial compiler values)
SourceCache: TCodeCache; // cache for source (units, include files, ...)
SourceChangeCache: TSourceChangeCache; // cache for write accesses
PPUCache: TPPUTools;
GlobalValues: TExpressionEvaluator;
DirectoryCachePool: TCTDirectoryCachePool;
FPCDefinesCache: TFPCDefinesCache;
@ -849,6 +851,7 @@ begin
DirectoryCachePool.OnIterateFPCUnitsFromSet:=@DirectoryCachePoolIterateFPCUnitsFromSet;
DefineTree.DirectoryCachePool:=DirectoryCachePool;
FPCDefinesCache:=TFPCDefinesCache.Create(nil);
PPUCache:=TPPUTools.Create(SourceCache);
FAddInheritedCodeToOverrideMethod:=true;
FAdjustTopLineDueToComment:=true;
FCatchExceptions:=true;
@ -884,6 +887,7 @@ begin
FreeAndNil(FPascalTools);
FDirectivesTools.FreeAndClear;
FreeAndNil(FDirectivesTools);
FreeAndNil(PPUCache);
FreeAndNil(FResourceTool);
{$IFDEF CTDEBUG}
DebugLn('[TCodeToolManager.Destroy] C');

View File

@ -71,16 +71,20 @@ type
ctdusInFilenameNormal, // unit 'in' filename -> filename
ctdusInFilenameCaseInsensitive, // unit 'in' filename case insensitive -> filename
ctdusUnitFileNormal, // AUnitName.ext (case depends on OS) -> filename
ctdusUnitFileCaseInsensitive // AUnitName.ext case insensitive -> filename
ctdusUnitFileCaseInsensitive, // AUnitName.ext case insensitive -> filename
ctdusPPUNormal, // UnitName (case depends on OS) => filename
ctdusPPUCaseInsensitive // UnitName case insensitive => filename
);
const
ctdusCaseNormal = [ctdusUnitNormal,
ctdusInFilenameNormal,
ctdusUnitFileNormal];
ctdusUnitFileNormal,
ctdusPPUNormal];
ctdusCaseInsensitive = [ctdusUnitCaseInsensitive,
ctdusInFilenameCaseInsensitive,
ctdusUnitFileCaseInsensitive];
ctdusUnitFileCaseInsensitive,
ctdusPPUCaseInsensitive];
type
@ -155,7 +159,7 @@ type
SearchPath: string; AnyCase: boolean): string;
function FindUnitSourceInCompletePath(var AUnitName, InFilename: string;
AnyCase: boolean): string;
function FindCompiledUnitInCompletePath(var ShortFilename: string;
function FindCompiledUnitInCompletePath(const AnUnitname: string;
AnyCase: boolean): string;
procedure IterateFPCUnitsInSet(const Iterate: TCTOnIterateFile);
procedure WriteListing;
@ -215,7 +219,7 @@ type
var AUnitName, InFilename: string;
AnyCase: boolean = false): string;
function FindCompiledUnitInCompletePath(const Directory: string;
var ShortFilename: string;
var AnUnitname: string;
AnyCase: boolean = false): string;
property FileTimeStamp: cardinal read FFileTimeStamp;
property ConfigTimeStamp: cardinal read FConfigTimeStamp;
@ -596,17 +600,15 @@ procedure TCTDirectoryCache.AddToCache(const UnitSrc: TCTDirectoryUnitSources;
const Search, Filename: string);
var
Files: TStringToStringTree;
CaseSensitive: Boolean;
begin
Files:=FUnitSources[UnitSrc].Files;
if Files=nil then begin
case UnitSrc of
ctdusUnitNormal: Files:=TStringToStringTree.Create(FilenamesCaseSensitive);
ctdusUnitCaseInsensitive: Files:=TStringToStringTree.Create(false);
ctdusInFilenameNormal: Files:=TFilenameToStringTree.Create(false);
ctdusInFilenameCaseInsensitive:Files:=TFilenameToStringTree.Create(true);
ctdusUnitFileNormal: Files:=TFilenameToStringTree.Create(false);
ctdusUnitFileCaseInsensitive: Files:=TFilenameToStringTree.Create(true);
end;
if UnitSrc in [ctdusUnitNormal,ctdusPPUNormal] then
CaseSensitive:=FilenamesCaseSensitive
else
CaseSensitive:=UnitSrc in ctdusCaseNormal;
Files:=TFilenameToStringTree.Create(CaseSensitive);
FUnitSources[UnitSrc].Files:=Files;
end;
Files[Search]:=Filename;
@ -1063,20 +1065,19 @@ begin
end;
function TCTDirectoryCache.FindCompiledUnitInCompletePath(
var ShortFilename: string; AnyCase: boolean): string;
const AnUnitname: string; AnyCase: boolean): string;
var
UnitPath: string;
NewShortFilename: String;
UnitSrc: TCTDirectoryUnitSources;
CurDir: String;
SearchCase: TCTSearchFileCase;
begin
Result:='';
if AnyCase then
UnitSrc:=ctdusUnitFileCaseInsensitive
UnitSrc:=ctdusPPUCaseInsensitive
else
UnitSrc:=ctdusUnitFileNormal;
if GetUnitSourceCacheValue(UnitSrc,ShortFilename,Result) then begin
UnitSrc:=ctdusPPUNormal;
if GetUnitSourceCacheValue(UnitSrc,AnUnitname,Result) then begin
// found in cache
if Result<>'' then begin
// unit found
@ -1095,19 +1096,13 @@ begin
// search in unit path
UnitPath:=Strings[ctdcsUnitPath];
Result:=SearchPascalFileInPath(ShortFilename,CurDir,UnitPath,';',SearchCase);
Result:=SearchPascalFileInPath(AnUnitname+'.ppu',CurDir,UnitPath,';',SearchCase);
if Result='' then begin
// search in unit set
Result:=FindCompiledUnitInUnitSet(ShortFilename);
end;
if Result<>'' then begin
NewShortFilename:=ExtractFileName(Result);
if (NewShortFilename<>lowercase(NewShortFilename))
and (ShortFilename<>NewShortFilename) then
ShortFilename:=NewShortFilename;
Result:=FindCompiledUnitInUnitSet(AnUnitname);
end;
AddToCache(UnitSrc,ShortFilename,Result);
AddToCache(UnitSrc,AnUnitname,Result);
end;
end;
@ -1382,13 +1377,13 @@ begin
end;
function TCTDirectoryCachePool.FindCompiledUnitInCompletePath(
const Directory: string; var ShortFilename: string; AnyCase: boolean
const Directory: string; var AnUnitname: string; AnyCase: boolean
): string;
var
Cache: TCTDirectoryCache;
begin
Cache:=GetCache(Directory,true,false);
Result:=Cache.FindCompiledUnitInCompletePath(ShortFilename,AnyCase);
Result:=Cache.FindCompiledUnitInCompletePath(AnUnitname,AnyCase);
end;
{ TCTDirectoryListing }

View File

@ -35,7 +35,8 @@ uses
// IDEIntf
IDECommands, MenuIntf, ProjectIntf, LazIDEIntf, IDEDialogs, IDEWindowIntf,
// codetools
BasicCodeTools, FileProcs, CodyStrConsts, CodeToolManager, CodeCache;
BasicCodeTools, FileProcs, CodyStrConsts, CodeToolManager, CodeCache,
PPUCodeTools;
const
PPUFileNotFound = ' ';
@ -358,10 +359,16 @@ var
Code: TCodeBuffer;
MainUsesSection: TStrings;
ImplementationUsesSection: TStrings;
ProjectDir: String;
BaseDir: String;
Scanned: Boolean;
PPUTool: TPPUTool;
OutputDir: String;
begin
StartTime:=Now;
ProjectDir:=ExtractFilePath(AProject.ProjectInfoFile);
BaseDir:=ExtractFilePath(AProject.ProjectInfoFile);
OutputDir:=AProject.LazCompilerOptions.GetUnitOutputDirectory(false);
while FSearchingItems.Count>0 do begin
Node:=FSearchingItems.Root;
Item:=TPPUListItem(Node.Data);
@ -370,17 +377,22 @@ begin
if Item.SrcFile='' then begin
// search source
debugln(['TPPUListDialog.OnIdle search source of ',AnUnitName]);
//debugln(['TPPUListDialog.OnIdle search source of ',AnUnitName]);
InFilename:='';
Item.SrcFile:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
'',AnUnitName,InFilename);
BaseDir,AnUnitName,InFilename);
end;
if Item.PPUFile='' then begin
// search ppu file
debugln(['TPPUListDialog.OnIdle search ppu of ',AnUnitName]);
//debugln(['TPPUListDialog.OnIdle search ppu of ',AnUnitName]);
Item.PPUFile:=CodeToolBoss.DirectoryCachePool.FindCompiledUnitInCompletePath(
ProjectDir,AnUnitName);
BaseDir,AnUnitName);
if (Item.PPUFile='') and (OutputDir<>'') then begin
// fallback: search in output directory
Item.PPUFile:=SearchPascalFileInDir(AnUnitName+'.ppu',OutputDir,
ctsfcLoUpCase);
end;
Item.OFile:=ChangeFileExt(Item.PPUFile,'.o');
if not FileExistsCached(Item.PPUFile) then
Item.PPUFile:=PPUFileNotFound
@ -394,14 +406,32 @@ begin
if Item.UsesUnits=nil then begin
Item.UsesUnits:=TStringList.Create;
Item.UsedByUnits:=TStringList.Create;
debugln(['TPPUListDialog.OnIdle search used units of ',AnUnitName]);
if Item.UsedByUnits=nil then
Item.UsedByUnits:=TStringList.Create;
//debugln(['TPPUListDialog.OnIdle search used units of ',AnUnitName]);
// scan for used units
Scanned:=false;
if Item.PPUFile<>PPUFileNotFound then begin
debugln(['TPPUListDialog.OnIdle search used units of ppu "',Item.PPUFile,'"']);
end else if Item.SrcFile<>'' then begin
debugln(['TPPUListDialog.OnIdle search used units of source "',Item.SrcFile,'"']);
//debugln(['TPPUListDialog.OnIdle search used units of ppu "',Item.PPUFile,'" ...']);
PPUTool:=CodeToolBoss.PPUCache.LoadFile(Item.PPUFile,true,false);
if (PPUTool<>nil) and (PPUTool.ErrorMsg='') then begin
//debugln(['TPPUListDialog.OnIdle parsed ppu "',Item.PPUFile,'"']);
MainUsesSection:=nil;
ImplementationUsesSection:=nil;
try
PPUTool.PPU.GetMainUsesSectionNames(MainUsesSection);
AddUses(Item,MainUsesSection);
PPUTool.PPU.GetImplementationUsesSectionNames(ImplementationUsesSection);
AddUses(Item,ImplementationUsesSection);
Scanned:=true;
finally
MainUsesSection.Free;
ImplementationUsesSection.Free;
end;
end;
end;
if (not Scanned) and (Item.SrcFile<>'') then begin
//debugln(['TPPUListDialog.OnIdle search used units of source "',Item.SrcFile,'"']);
Code:=CodeToolBoss.LoadFile(Item.SrcFile,true,false);
if Code<>nil then begin
MainUsesSection:=nil;
@ -436,10 +466,10 @@ var
UsedUnit: TPPUListItem;
begin
if UsedUnits=nil then exit;
debugln(['TPPUListDialog.AddUses Src=',SrcItem.TheUnitName,' UsedUnits="',UsedUnits.DelimitedText,'"']);
//debugln(['TPPUListDialog.AddUses Src=',SrcItem.TheUnitName,' UsedUnits="',UsedUnits.DelimitedText,'"']);
for i:=0 to UsedUnits.Count-1 do begin
AnUnitName:=UsedUnits[i];
debugln(['TPPUListDialog.AddUses ',SrcItem.TheUnitName,' uses ',AnUnitName]);
//debugln(['TPPUListDialog.AddUses ',SrcItem.TheUnitName,' uses ',AnUnitName]);
UsedUnit:=FindUnit(AnUnitName);
if UsedUnit=nil then begin
// new unit

View File

@ -30,9 +30,189 @@ unit PPUCodeTools;
interface
uses
Classes, SysUtils;
Classes, SysUtils, PPUParser, CodeCache, AVL_Tree, FileProcs;
type
{ TPPUTool }
TPPUTool = class
public
PPU: TPPU;
Code: TCodeBuffer;
CodeChangeStep: integer;
ErrorMsg: string;
constructor Create(aCode: TCodeBuffer);
destructor Destroy; override;
end;
{ TPPUTools }
TPPUTools = class
private
fItems: TAVLTree; // tree of TPPUTool sorted for Code
FSourceCache: TCodeCache;
public
constructor Create(SrcCache: TCodeCache);
destructor Destroy; override;
procedure ClearCaches;
property SourceCache: TCodeCache read FSourceCache;
function FindFile(Code: TCodeBuffer): TPPUTool;
function FindFile(const ExpandedFilename: string): TPPUTool;
function LoadFile(const ExpandedFilename: string;
UpdateFromDisk, Revert: boolean): TPPUTool;
// uses section
procedure GetMainUsesSectionNames(Code: TCodeBuffer; var List: TStrings);
procedure GetImplementationUsesSectionNames(Code: TCodeBuffer; var List: TStrings);
end;
function ComparePPUTools(Tool1, Tool2: Pointer): integer;
function CompareCodeWithPPUTool(Code, Tool: Pointer): integer;
implementation
function ComparePPUTools(Tool1, Tool2: Pointer): integer;
begin
Result:=ComparePointers(TPPUTool(Tool1).Code,TPPUTool(Tool2).Code);
end;
function CompareCodeWithPPUTool(Code, Tool: Pointer): integer;
begin
Result:=ComparePointers(Code,TPPUTool(Tool).Code);
end;
{ TPPUTools }
constructor TPPUTools.Create(SrcCache: TCodeCache);
begin
FSourceCache:=SrcCache;
fItems:=TAVLTree.Create(@ComparePPUTools);
end;
destructor TPPUTools.Destroy;
begin
fItems.FreeAndClear;
FreeAndNil(fItems);
FSourceCache:=nil;
inherited Destroy;
end;
procedure TPPUTools.ClearCaches;
var
Node: TAVLTreeNode;
Tool: TPPUTool;
begin
Node:=fItems.FindLowest;
while Node<>nil do begin
Tool:=TPPUTool(Node.Data);
FreeAndNil(Tool.PPU);
Tool.ErrorMsg:='';
Node:=fItems.FindSuccessor(Node);
end;
end;
function TPPUTools.FindFile(Code: TCodeBuffer): TPPUTool;
var
Node: TAVLTreeNode;
begin
Result:=nil;
if Code=nil then exit;
Node:=fItems.FindKey(Code,@CompareCodeWithPPUTool);
if Node<>nil then
Result:=TPPUTool(Node.Data);
end;
function TPPUTools.FindFile(const ExpandedFilename: string): TPPUTool;
var
Code: TCodeBuffer;
begin
Code:=SourceCache.FindFile(ExpandedFilename);
if Code<>nil then
Result:=FindFile(Code)
else
Result:=nil;
end;
function TPPUTools.LoadFile(const ExpandedFilename: string; UpdateFromDisk,
Revert: boolean): TPPUTool;
var
Code: TCodeBuffer;
ss: TStringStream;
begin
Result:=FindFile(ExpandedFilename);
if (not UpdateFromDisk) and (not Revert) then begin
// no update needed
if Result<>nil then exit;
Code:=SourceCache.FindFile(ExpandedFilename);
if (Code=nil) or Code.IsDeleted then exit(nil);
end;
// load file
Code:=SourceCache.LoadFile(ExpandedFilename);
if Code=nil then exit(nil);
if Revert then begin
if not Code.Revert then
exit(nil);
end else if UpdateFromDisk and Code.AutoRevertFromDisk
and Code.FileNeedsUpdate then begin
//debugln(['TPPUTools.LoadFile ',ExpandedFilename,' AutoRevert=',Result.AutoRevertFromDisk,' Modified=',Result.Modified,' NeedLoad=',Result.FileNeedsUpdate]);
Code.Reload;
end;
// check if tool needs update
if Result=nil then begin
Result:=TPPUTool.Create(Code);
fItems.Add(Result);
end;
Result.Code:=Code;
if (Result.PPU<>nil) and (Result.CodeChangeStep=Code.ChangeStep) then
exit;
//debugln(['TPPUTools.LoadFile parsing ppu ',Code.Filename,' ...']);
Result.ErrorMsg:='';
if Result.PPU=nil then
Result.PPU:=TPPU.Create;
ss:=TStringStream.Create(Code.Source);
try
try
Result.PPU.LoadFromStream(ss);
except
on E: Exception do begin
Result.ErrorMsg:=E.Message;
debugln(['TPPUTools.LoadFile ',Code.Filename,' ERROR: ', Result.ErrorMsg]);
end;
end;
finally
ss.Free;
end;
end;
procedure TPPUTools.GetMainUsesSectionNames(Code: TCodeBuffer;
var List: TStrings);
begin
end;
procedure TPPUTools.GetImplementationUsesSectionNames(Code: TCodeBuffer;
var List: TStrings);
begin
end;
{ TPPUTool }
constructor TPPUTool.Create(aCode: TCodeBuffer);
begin
Code:=aCode;
CodeChangeStep:=Code.ChangeStep;
end;
destructor TPPUTool.Destroy;
begin
FreeAndNil(PPU);
inherited Destroy;
end;
end.

View File

@ -546,6 +546,7 @@ type
function GetLibraryPath(RelativeToBaseDir: boolean;
Parsed: TCompilerOptionsParseType = coptParsed;
WithBaseDir: boolean = true): string;
function GetUnitOutputDirectory(RelativeToBaseDir: boolean): string; override;
function GetUnitOutPath(RelativeToBaseDir: boolean;
Parsed: TCompilerOptionsParseType = coptParsed): string;
function GetObjectPath(RelativeToBaseDir: boolean;
@ -1915,6 +1916,12 @@ begin
WithBaseDir);
end;
function TBaseCompilerOptions.GetUnitOutputDirectory(RelativeToBaseDir: boolean
): string;
begin
Result:=GetUnitOutPath(RelativeToBaseDir);
end;
function TBaseCompilerOptions.GetUnitOutPath(RelativeToBaseDir: boolean;
Parsed: TCompilerOptionsParseType): string;
begin

View File

@ -303,6 +303,7 @@ type
function IsActive: boolean; virtual;
function TrimCustomOptions(o: string): string; virtual; abstract;
function CreatePPUFilename(const SourceFileName: string): string; virtual; abstract;
function GetUnitOutputDirectory(RelativeToBaseDir: boolean): string; virtual; abstract;
public
property Owner: TObject read fOwner write fOwner;
property Modified: boolean read GetModified write SetModified;