fcl-passrc: parser: create usesclause

git-svn-id: trunk@36006 -
This commit is contained in:
Mattias Gaertner 2017-04-29 10:50:00 +00:00
parent d5d53e7017
commit d7163d3854
7 changed files with 211 additions and 118 deletions

View File

@ -1137,7 +1137,7 @@ type
Access: TResolvedRefAccess); virtual;
procedure AccessExpr(Expr: TPasExpr; Access: TResolvedRefAccess);
procedure FinishModule(CurModule: TPasModule); virtual;
procedure FinishUsesList; virtual;
procedure FinishUsesClause; virtual;
procedure FinishTypeSection(El: TPasDeclarations); virtual;
procedure FinishTypeDef(El: TPasType); virtual;
procedure FinishEnumType(El: TPasEnumType); virtual;
@ -3025,54 +3025,56 @@ begin
{$ENDIF}
end;
procedure TPasResolver.FinishUsesList;
procedure TPasResolver.FinishUsesClause;
var
Section: TPasSection;
i: Integer;
El, PublicEl: TPasElement;
PublicEl, UseModule: TPasElement;
Scope: TPasSectionScope;
UsesScope: TPasIdentifierScope;
UseUnit: TPasUsesUnit;
begin
CheckTopScope(TPasSectionScope);
Scope:=TPasSectionScope(TopScope);
Section:=TPasSection(Scope.Element);
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.FinishUsesList Section=',Section.ClassName,' Section.UsesList.Count=',Section.UsesList.Count);
writeln('TPasResolver.FinishUsesClause Section=',Section.ClassName,' Section.UsesList.Count=',Section.UsesList.Count);
{$ENDIF}
for i:=0 to Section.UsesList.Count-1 do
begin
El:=TPasElement(Section.UsesList[i]);
UseUnit:=Section.UsesClause[i];
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.FinishUsesList ',GetObjName(El));
writeln('TPasResolver.FinishUsesClause ',GetObjName(UseUnit));
{$ENDIF}
if (El.ClassType=TProgramSection) then
RaiseInternalError(20160922163346,'used unit is a program: '+GetObjName(El));
UseModule:=UseUnit.Module;
if (UseModule.ClassType=TProgramSection) then
RaiseInternalError(20160922163346,'used unit is a program: '+GetObjName(UseModule));
// add unitname as identifier
AddIdentifier(Scope,El.Name,El,pikSimple);
AddIdentifier(Scope,UseUnit.Name,UseModule,pikSimple);
// check used unit
PublicEl:=nil;
if (El.ClassType=TLibrarySection) then
PublicEl:=El
else if (El.ClassType=TPasModule) then
PublicEl:=TPasModule(El).InterfaceSection;
if (UseModule.ClassType=TLibrarySection) then
PublicEl:=UseModule
else if (UseModule.ClassType=TPasModule) then
PublicEl:=TPasModule(UseModule).InterfaceSection;
if PublicEl=nil then
RaiseInternalError(20160922163352,'uses element has no interface section: '+GetObjName(El));
RaiseInternalError(20160922163352,'uses element has no interface section: '+GetObjName(UseModule));
if PublicEl.CustomData=nil then
RaiseInternalError(20160922163358,'uses element has no resolver data: '
+El.Name+'->'+GetObjName(PublicEl));
+UseUnit.Name+'->'+GetObjName(PublicEl));
if not (PublicEl.CustomData is TPasIdentifierScope) then
RaiseInternalError(20160922163403,'uses element has invalid resolver data: '
+El.Name+'->'+GetObjName(PublicEl)+'->'+PublicEl.CustomData.ClassName);
+UseUnit.Name+'->'+GetObjName(PublicEl)+'->'+PublicEl.CustomData.ClassName);
UsesScope:=TPasIdentifierScope(PublicEl.CustomData);
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.FinishUsesList Add UsesScope=',GetObjName(UsesScope));
writeln('TPasResolver.FinishUsesClause Add UsesScope=',GetObjName(UsesScope));
{$ENDIF}
Scope.UsesList.Add(UsesScope);
EmitElementHints(Section,El);
EmitElementHints(Section,UseUnit);
end;
end;
@ -8569,7 +8571,7 @@ procedure TPasResolver.FinishScope(ScopeType: TPasScopeType; El: TPasElement);
begin
case ScopeType of
stModule: FinishModule(El as TPasModule);
stUsesList: FinishUsesList;
stUsesClause: FinishUsesClause;
stTypeSection: FinishTypeSection(El as TPasDeclarations);
stTypeDef: FinishTypeDef(El as TPasType);
stConstDef: FinishConstDef(El as TPasConst);
@ -11656,11 +11658,18 @@ begin
ResolvedEl.IdentEl:=El;
ResolvedEl.Flags:=[rrfReadable,rrfWritable];
end
else if El is TPasModule then
else if ElClass=TPasUsesUnit then
begin
if TPasUsesUnit(El).Module is TPasModule then
SetResolverIdentifier(ResolvedEl,btModule,TPasUsesUnit(El).Module,nil,[])
else
RaiseNotYetImplemented(20170429112047,TPasUsesUnit(El).Module);
end
else if El.InheritsFrom(TPasModule) then
SetResolverIdentifier(ResolvedEl,btModule,El,nil,[])
else if ElClass=TNilExpr then
SetResolverValueExpr(ResolvedEl,btNil,FBaseTypes[btNil],TNilExpr(El),[rrfReadable])
else if El is TPasProcedure then
else if El.InheritsFrom(TPasProcedure) then
begin
SetResolverIdentifier(ResolvedEl,btProc,El,TPasProcedure(El).ProcType,[rrfCanBeStatement]);
if El is TPasFunction then
@ -11668,7 +11677,7 @@ begin
// Note: the readability of TPasConstructor depends on the context
// Note: implicit calls are handled in TPrimitiveExpr
end
else if El is TPasProcedureType then
else if El.InheritsFrom(TPasProcedureType) then
begin
SetResolverIdentifier(ResolvedEl,btContext,El,TPasProcedureType(El),[rrfCanBeStatement]);
// Note: implicit calls are handled in TPrimitiveExpr

View File

@ -195,7 +195,7 @@ begin
If not Assigned(ASection) then exit;
if ASection.UsesList.Count=length(ASection.UsesClause) then
For I:=0 to length(ASection.UsesClause)-1 do
List.Add(ASection.UsesClause[i].Identifier)
List.Add(ASection.UsesClause[i].Name)
else
For I:=0 to ASection.UsesList.Count-1 do
List.Add(TPasElement(ASection.UsesList[i]).Name);

View File

@ -319,10 +319,9 @@ type
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override;
public
Expr: TPasExpr;
Identifier: string; // e.g. 'name.space.unitname'
Expr: TPasExpr; // name expression
InFilename: TPrimitiveExpr; // Kind=pekString, can be nil
Module: TPasElement; // TPasUnresolvedTypeRef or TPasModule
Module: TPasElement; // TPasUnresolvedUnitRef or TPasModule
end;
TPasUsesClause = array of TPasUsesUnit;
@ -332,12 +331,13 @@ type
public
constructor Create(const AName: string; AParent: TPasElement); override;
destructor Destroy; override;
procedure AddUnitToUsesList(const AUnitName: string);
function AddUnitToUsesList(const AUnitName: string; aName: TPasExpr = nil;
InFilename: TPrimitiveExpr = nil; aModule: TPasElement = nil): TPasUsesUnit;
function ElementTypeName: string; override;
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override;
public
UsesList: TFPList; // kept for compatibility, see UsesClause Module
UsesList: TFPList; // kept for compatibility, see TPasUsesUnit.Module
UsesClause: TPasUsesClause;
end;
@ -4028,14 +4028,26 @@ begin
{$IFDEF VerbosePasTreeMem}writeln('TPasSection.Destroy END');{$ENDIF}
end;
procedure TPasSection.AddUnitToUsesList(const AUnitName: string);
function TPasSection.AddUnitToUsesList(const AUnitName: string;
aName: TPasExpr; InFilename: TPrimitiveExpr; aModule: TPasElement
): TPasUsesUnit;
var
l: Integer;
begin
UsesList.Add(TPasUnresolvedTypeRef.Create(AUnitName, Self));
if (InFilename<>nil) and (InFilename.Kind<>pekString) then
raise Exception.Create('');
if aModule=nil then
aModule:=TPasUnresolvedUnitRef.Create(AUnitName, Self);
l:=length(UsesClause);
SetLength(UsesClause,l+1);
UsesClause[l]:=TPasUsesUnit.Create(AUnitName,Self);
Result:=TPasUsesUnit.Create(AUnitName,Self);
UsesClause[l]:=Result;
Result.Expr:=aName;
Result.InFilename:=InFilename;
Result.Module:=aModule;
UsesList.Add(aModule);
aModule.AddRef;
end;
function TPasSection.ElementTypeName: string;

View File

@ -740,11 +740,11 @@ end;
procedure TPasAnalyzer.UseSection(Section: TPasSection; Mode: TPAUseMode);
// called by UseModule
var
UsesList: TFPList;
i: Integer;
UsedModule: TPasModule;
Decl: TPasElement;
OnlyExports: Boolean;
UsesClause: TPasUsesClause;
begin
// Section is TProgramSection, TLibrarySection, TInterfaceSection, TImplementationSection
if Mode=paumElement then
@ -760,12 +760,12 @@ begin
{$ENDIF}
// used units
UsesList:=Section.UsesList;
for i:=0 to UsesList.Count-1 do
UsesClause:=Section.UsesClause;
for i:=0 to length(UsesClause)-1 do
begin
if TObject(UsesList[i]) is TPasModule then
if UsesClause[i].Module is TPasModule then
begin
UsedModule:=TPasModule(UsesList[i]);
UsedModule:=TPasModule(UsesClause[i].Module);
if ScopeModule=nil then
// whole program analysis
UseModule(UsedModule,paumAllExports)
@ -1563,21 +1563,21 @@ end;
procedure TPasAnalyzer.EmitSectionHints(Section: TPasSection);
var
UsesList: TFPList;
i: Integer;
UsedModule, aModule: TPasModule;
UsesClause: TPasUsesClause;
begin
{$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.EmitSectionHints ',GetElModName(Section));
{$ENDIF}
// initialization, program or library sections
aModule:=Section.GetModule;
UsesList:=Section.UsesList;
for i:=0 to UsesList.Count-1 do
UsesClause:=Section.UsesClause;
for i:=0 to length(UsesClause)-1 do
begin
if TObject(UsesList[i]) is TPasModule then
if UsesClause[i].Module is TPasModule then
begin
UsedModule:=TPasModule(UsesList[i]);
UsedModule:=TPasModule(UsesClause[i].Module);
if CompareText(UsedModule.Name,'system')=0 then continue;
if FindNode(UsedModule)=nil then
EmitMessage(20170311191725,mtHint,nPAUnitNotUsed,sPAUnitNotUsed,

View File

@ -134,7 +134,7 @@ resourcestring
type
TPasScopeType = (
stModule, // e.g. unit, program, library
stUsesList,
stUsesClause,
stTypeSection,
stTypeDef, // e.g. a TPasType
stConstDef, // e.g. a TPasConst
@ -312,7 +312,8 @@ type
function DoParseExpression(AParent: TPaselement;InitExpr: TPasExpr=nil; AllowEqual : Boolean = True): TPasExpr;
function DoParseConstValueExpression(AParent: TPasElement): TPasExpr;
function CheckPackMode: TPackMode;
function CheckUseUnit(ASection: TPasSection; AUnitName : string): TPasElement;
function AddUseUnit(ASection: TPasSection; AUnitName : string;
NameExpr: TPasExpr; InFileExpr: TPrimitiveExpr): TPasElement;
procedure CheckImplicitUsedUnits(ASection: TPasSection);
// Overload handling
procedure AddProcOrFunction(Decs: TPasDeclarations; AProc: TPasProcedure);
@ -2425,14 +2426,14 @@ begin
end;
procedure TPasParser.ParseOptionalUsesList(ASection: TPasSection);
// checks if next token is Uses keyword and read uses list
// checks if next token is Uses keyword and reads the uses list
begin
NextToken;
if CurToken=tkuses then
ParseUsesList(ASection)
else begin
CheckImplicitUsedUnits(ASection);
Engine.FinishScope(stUsesList,ASection);
Engine.FinishScope(stUsesClause,ASection);
UngetToken;
end;
end;
@ -2852,38 +2853,64 @@ begin
SetBlock(declNone);
end;
function TPasParser.CheckUseUnit(ASection: TPasSection; AUnitName: string
): TPasElement;
function TPasParser.AddUseUnit(ASection: TPasSection; AUnitName: string;
NameExpr: TPasExpr; InFileExpr: TPrimitiveExpr): TPasElement;
procedure CheckDuplicateInUsesList(AUnitName : string; UsesList: TFPList);
procedure CheckDuplicateInUsesList(AUnitName : string; UsesClause: TPasUsesClause);
var
i: Integer;
begin
if UsesList=nil then exit;
for i:=0 to UsesList.Count-1 do
if CompareText(AUnitName,TPasModule(UsesList[i]).Name)=0 then
if UsesClause=nil then exit;
for i:=0 to length(UsesClause)-1 do
if CompareText(AUnitName,UsesClause[i].Name)=0 then
ParseExc(nParserDuplicateIdentifier,SParserDuplicateIdentifier,[AUnitName]);
end;
var
UnitRef: TPasElement;
begin
if CompareText(AUnitName,CurModule.Name)=0 then
begin
// System is implicit, except when parsing system unit.
if CompareText(AUnitName,'System')=0 then
exit;
ParseExc(nParserDuplicateIdentifier,SParserDuplicateIdentifier,[AUnitName]);
end;
CheckDuplicateInUsesList(AUnitName,ASection.UsesList);
if ASection.ClassType=TImplementationSection then
CheckDuplicateInUsesList(AUnitName,CurModule.InterfaceSection.UsesList);
Result:=nil;
try
{$IFDEF VerbosePasParser}
writeln('TPasParser.AddUseUnit AUnitName=',AUnitName,' CurModule.Name=',CurModule.Name);
{$ENDIF}
if CompareText(AUnitName,CurModule.Name)=0 then
begin
if CompareText(AUnitName,'System')=0 then
exit; // for compatibility ignore implicit use of system in system
ParseExc(nParserDuplicateIdentifier,SParserDuplicateIdentifier,[AUnitName]);
end;
CheckDuplicateInUsesList(AUnitName,ASection.UsesClause);
if ASection.ClassType=TImplementationSection then
CheckDuplicateInUsesList(AUnitName,CurModule.InterfaceSection.UsesClause);
result := Engine.FindModule(AUnitName); // should we resolve module here when "IN" filename is not known yet?
if Assigned(result) then
result.AddRef
else
Result := TPasUnresolvedUnitRef(CreateElement(TPasUnresolvedUnitRef,
AUnitName, ASection));
ASection.UsesList.Add(Result);
UnitRef := Engine.FindModule(AUnitName); // should we resolve module here when "IN" filename is not known yet?
if Assigned(UnitRef) then
UnitRef.AddRef
else
UnitRef := TPasUnresolvedUnitRef(CreateElement(TPasUnresolvedUnitRef,
AUnitName, ASection));
Result:=ASection.AddUnitToUsesList(AUnitName,NameExpr,InFileExpr,UnitRef);
if InFileExpr<>nil then
begin
if UnitRef is TPasModule then
begin
if TPasModule(UnitRef).Filename='' then
TPasModule(UnitRef).Filename:=InFileExpr.Value;
end
else if UnitRef is TPasUnresolvedUnitRef then
TPasUnresolvedUnitRef(UnitRef).FileName:=InFileExpr.Value;
end;
finally
if Result=nil then
begin
if NameExpr<>nil then
NameExpr.Release;
if InFileExpr<>nil then
InFileExpr.Release;
end;
end;
end;
procedure TPasParser.CheckImplicitUsedUnits(ASection: TPasSection);
@ -2894,43 +2921,60 @@ begin
begin
// load implicit units, like 'System'
for i:=0 to ImplicitUses.Count-1 do
CheckUseUnit(ASection,ImplicitUses[i]);
AddUseUnit(ASection,ImplicitUses[i],nil,nil);
end;
end;
// Starts after the "uses" token
procedure TPasParser.ParseUsesList(ASection: TPasSection);
var
AUnitName: String;
Element: TPasElement;
AUnitName, aName: String;
NameExpr: TPasExpr;
InFileExpr: TPrimitiveExpr;
FreeExpr: Boolean;
begin
CheckImplicitUsedUnits(ASection);
Repeat
AUnitName := ExpectIdentifier;
NextToken;
while CurToken = tkDot do
begin
ExpectIdentifier;
AUnitName := AUnitName + '.' + CurTokenString;
NameExpr:=nil;
InFileExpr:=nil;
FreeExpr:=true;
try
Repeat
FreeExpr:=true;
AUnitName := ExpectIdentifier;
NameExpr:=CreatePrimitiveExpr(ASection,pekString,AUnitName);
NextToken;
end;
Element := CheckUseUnit(ASection,AUnitName);
if (CurToken=tkin) then
while CurToken = tkDot do
begin
ExpectToken(tkString);
if (Element is TPasModule) and (TPasmodule(Element).filename='') then
TPasModule(Element).FileName:=curtokenstring
else if (Element is TPasUnresolvedUnitRef) then
TPasUnresolvedUnitRef(Element).FileName:=curtokenstring;
NextToken;
ExpectIdentifier;
aName:=CurTokenString;
AUnitName := AUnitName + '.' + aName;
AddToBinaryExprChain(NameExpr,CreatePrimitiveExpr(ASection,pekString,aName),eopSubIdent);
NextToken;
end;
if (CurToken=tkin) then
begin
ExpectToken(tkString);
InFileExpr:=CreatePrimitiveExpr(ASection,pekString,CurTokenString);
NextToken;
end;
FreeExpr:=false;
AddUseUnit(ASection,AUnitName,NameExpr,InFileExpr);
InFileExpr:=nil;
NameExpr:=nil;
if Not (CurToken in [tkComma,tkSemicolon]) then
ParseExc(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon);
Until (CurToken=tkSemicolon);
if Not (CurToken in [tkComma,tkSemicolon]) then
ParseExc(nParserExpectedCommaSemicolon,SParserExpectedCommaSemicolon);
Until (CurToken=tkSemicolon);
finally
if FreeExpr then
begin
NameExpr.Release;
InFileExpr.Release;
end;
end;
Engine.FinishScope(stUsesList,ASection);
Engine.FinishScope(stUsesClause,ASection);
end;
// Starts after the variable name

View File

@ -15,7 +15,7 @@ Type
private
function GetIf: TInterfaceSection;
function GetIm: TImplementationSection;
function CheckUnit(AIndex: Integer; const AName: String; AList: TFPList): TPasUnresolvedUnitRef;
function CheckUnit(AIndex: Integer; const AName: String; Section: TPasSection): TPasUnresolvedUnitRef;
Protected
Procedure ParseUnit;
Procedure ParseProgram;
@ -98,18 +98,32 @@ begin
end;
function TTestModuleParser.CheckUnit(AIndex: Integer; const AName: String;
AList: TFPList) : TPasUnresolvedUnitRef;
Section: TPasSection): TPasUnresolvedUnitRef;
Var
C : string;
AList: TFPList;
Clause: TPasUsesClause;
begin
Result:=nil;
C:='Unit '+IntTostr(AIndex)+' ';
AList:=Section.UsesList;
AssertNotNull('Have useslist',AList);
if (AIndex>=AList.Count) then
Fail(Format('Index %d larger than unit list count %d',[AIndex,AList.Count ]));
AssertNotNull('Have pascal element',AList[AIndex]);
AssertEquals(C+'Correct class',TPasUnresolvedUnitRef,TObject(AList[AIndex]).CLassType);
Result:=TPasUnresolvedUnitRef(AList[AIndex]);
Clause:=Section.UsesClause;
if AIndex>=length(Clause) then
Fail(Format('Index %d larger than unit list count %d',[AIndex,length(Clause) ]));
AssertNotNull('Have pascal element',Clause[AIndex]);
AssertEquals(C+'Correct class',TPasUsesUnit,Clause[AIndex].ClassType);
AssertNotNull(C+'Has Module',Clause[AIndex].Module);
AssertEquals(C+'Correct module class',TPasUnresolvedUnitRef,Clause[AIndex].Module.ClassType);
Result:=TPasUnresolvedUnitRef(Clause[AIndex].Module);
AssertEquals(C+'Unit name correct',AName,Result.Name);
end;
@ -119,8 +133,10 @@ begin
StartImplementation;
ParseUnit;
AssertEquals('Only system in interface units',1,IntfSection.UsesList.Count);
CheckUnit(0,'System',IntfSection.UsesList);
AssertEquals('Only system in interface units',1,length(IntfSection.UsesClause));
CheckUnit(0,'System',IntfSection);
AssertEquals('No implementation units',0,ImplSection.UsesList.Count);
AssertEquals('No implementation units',0,length(ImplSection.UsesClause));
end;
procedure TTestModuleParser.TestUnitOneUses;
@ -130,9 +146,11 @@ begin
StartImplementation;
ParseUnit;
AssertEquals('Two interface units',2,IntfSection.UsesList.Count);
CheckUnit(0,'System',IntfSection.UsesList);
CheckUnit(1,'a',IntfSection.UsesList);
AssertEquals('Two interface units',2,length(IntfSection.UsesClause));
CheckUnit(0,'System',IntfSection);
CheckUnit(1,'a',IntfSection);
AssertEquals('No implementation units',0,ImplSection.UsesList.Count);
AssertEquals('No implementation units',0,length(ImplSection.UsesClause));
end;
procedure TTestModuleParser.TestUnitTwoUses;
@ -141,11 +159,13 @@ begin
UsesClause(['a','b']);
StartImplementation;
ParseUnit;
AssertEquals('Two interface units',3,IntfSection.UsesList.Count);
CheckUnit(0,'System',IntfSection.UsesList);
CheckUnit(1,'a',IntfSection.UsesList);
CheckUnit(2,'b',IntfSection.UsesList);
AssertEquals('Three interface units',3,IntfSection.UsesList.Count);
AssertEquals('Three interface units',3,length(IntfSection.UsesClause));
CheckUnit(0,'System',IntfSection);
CheckUnit(1,'a',IntfSection);
CheckUnit(2,'b',IntfSection);
AssertEquals('No implementation units',0,ImplSection.UsesList.Count);
AssertEquals('No implementation units',0,length(ImplSection.UsesClause));
end;
procedure TTestModuleParser.TestUnitOneImplUses;
@ -155,9 +175,11 @@ begin
UsesClause(['a']);
ParseUnit;
AssertEquals('One implementation units',1,ImplSection.UsesList.Count);
CheckUnit(0,'a',ImplSection.UsesList);
AssertEquals('One implementation units',1,length(ImplSection.UsesClause));
CheckUnit(0,'a',ImplSection);
AssertEquals('Only system in interface units',1,IntfSection.UsesList.Count);
CheckUnit(0,'System',IntfSection.UsesList);
AssertEquals('Only system in interface units',1,length(IntfSection.UsesClause));
CheckUnit(0,'System',IntfSection);
end;
procedure TTestModuleParser.TestUnitTwoImplUses;
@ -167,10 +189,12 @@ begin
UsesClause(['a','b']);
ParseUnit;
AssertEquals('One interface unit',1,IntfSection.UsesList.Count);
CheckUnit(0,'System',IntfSection.UsesList);
AssertEquals('One interface unit',1,length(IntfSection.UsesClause));
CheckUnit(0,'System',IntfSection);
AssertEquals('Two implementation units',2,ImplSection.UsesList.Count);
CheckUnit(0,'a',ImplSection.UsesList);
CheckUnit(1,'b',ImplSection.UsesList);
AssertEquals('Two implementation units',2,length(ImplSection.UsesClause));
CheckUnit(0,'a',ImplSection);
CheckUnit(1,'b',ImplSection);
end;
procedure TTestModuleParser.TestEmptyUnitInitialization;
@ -260,8 +284,9 @@ begin
Add('begin');
ParseProgram;
AssertEquals('Two interface units',2, PasProgram.ProgramSection.UsesList.Count);
CheckUnit(0,'System',PasProgram.ProgramSection.UsesList);
CheckUnit(1,'a',PasProgram.ProgramSection.UsesList);
AssertEquals('Two interface units',2, length(PasProgram.ProgramSection.UsesClause));
CheckUnit(0,'System',PasProgram.ProgramSection);
CheckUnit(1,'a',PasProgram.ProgramSection);
end;
procedure TTestModuleParser.TestEmptyProgramUsesTwoUnits;
@ -270,9 +295,10 @@ begin
Add('begin');
ParseProgram;
AssertEquals('Three interface units',3, PasProgram.ProgramSection.UsesList.Count);
CheckUnit(0,'System',PasProgram.ProgramSection.UsesList);
CheckUnit(1,'a',PasProgram.ProgramSection.UsesList);
CheckUnit(2,'b',PasProgram.ProgramSection.UsesList);
AssertEquals('Three interface unit',3, length(PasProgram.ProgramSection.UsesClause));
CheckUnit(0,'System',PasProgram.ProgramSection);
CheckUnit(1,'a',PasProgram.ProgramSection);
CheckUnit(2,'b',PasProgram.ProgramSection);
end;
procedure TTestModuleParser.TestEmptyProgramUsesUnitIn;
@ -284,11 +310,12 @@ begin
UsesClause(['a in ''../a.pas''','b']);
Add('begin');
ParseProgram;
AssertEquals('One interface unit',3, PasProgram.ProgramSection.UsesList.Count);
CheckUnit(0,'System',PasProgram.ProgramSection.UsesList);
U:=CheckUnit(1,'a',PasProgram.ProgramSection.UsesList);
AssertEquals('Three interface unit',3, PasProgram.ProgramSection.UsesList.Count);
AssertEquals('Three interface unit',3, length(PasProgram.ProgramSection.UsesClause));
CheckUnit(0,'System',PasProgram.ProgramSection);
U:=CheckUnit(1,'a',PasProgram.ProgramSection);
AssertEquals('Filename','''../a.pas''',U.FileName);
CheckUnit(2,'b',PasProgram.ProgramSection.UsesList);
CheckUnit(2,'b',PasProgram.ProgramSection);
end;
procedure TTestModuleParser.TestEmptyLibrary;
@ -305,8 +332,9 @@ begin
ParseLibrary;
AssertEquals('Correct class',TPasLibrary,Module.ClassType);
AssertEquals('Two interface units',2, PasLibrary.LibrarySection.UsesList.Count);
CheckUnit(0,'System',PasLibrary.LibrarySection.UsesList);
CheckUnit(1,'a',PasLibrary.LibrarySection.UsesList);
AssertEquals('Two interface units',2, length(PasLibrary.LibrarySection.UsesClause));
CheckUnit(0,'System',PasLibrary.LibrarySection);
CheckUnit(1,'a',PasLibrary.LibrarySection);
end;
procedure TTestModuleParser.TestEmptyLibraryExports;

View File

@ -16,7 +16,7 @@ type
FAnalyser : TPasSrcAnalysis;
FSrc : TStrings;
FList : TStrings;
FStream: TmemoryStream;
FStream: TMemoryStream;
protected
procedure SetUp; override;
procedure TearDown; override;