diff --git a/packages/fcl-passrc/src/pasuseanalyzer.pas b/packages/fcl-passrc/src/pasuseanalyzer.pas index 9cebe564fc..9f914c7193 100644 --- a/packages/fcl-passrc/src/pasuseanalyzer.pas +++ b/packages/fcl-passrc/src/pasuseanalyzer.pas @@ -147,15 +147,15 @@ type end; TPasAnalyzerOption = ( - paoKeepPublished, // when a class is used, all its published members are used as well paoOnlyExports // default: use all class members accessible from outside (protected, but not private) ); TPasAnalyzerOptions = set of TPasAnalyzerOption; TPAUseMode = ( - paumElement, // mark element - paumAllPublic, // mark element and descend into children and mark public identifiers - paumAllExports // do not mark element and descend into children and mark exports + paumElement, // Mark element. Do not descend into children. + paumAllPublic, // Mark element and descend into children and mark public identifiers + paumAllExports, // Do not mark element. Descend into children and mark exports. + paumPublished // Mark element and its type and descend into children and mark published identifiers ); TPAUseModes = set of TPAUseMode; @@ -188,6 +188,7 @@ type function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean; procedure UseElement(El: TPasElement; Access: TResolvedRefAccess; UseFull: boolean); virtual; + procedure UsePublished(El: TPasElement); virtual; procedure UseModule(aModule: TPasModule; Mode: TPAUseMode); virtual; procedure UseSection(Section: TPasSection; Mode: TPAUseMode); virtual; procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual; @@ -221,6 +222,7 @@ type function FindElement(El: TPasElement): TPAElement; // utility function IsUsed(El: TPasElement): boolean; // valid after calling Analyze* + function IsTypeInfoUsed(El: TPasElement): boolean; // valid after calling Analyze* function IsModuleInternal(El: TPasElement): boolean; function IsExport(El: TPasElement): boolean; function IsIdentifier(El: TPasElement): boolean; @@ -615,6 +617,80 @@ begin RaiseNotSupported(20170307090947,El); end; +procedure TPasAnalyzer.UsePublished(El: TPasElement); +// mark typeinfo, do not +var + C: TClass; + Members: TFPList; + i: Integer; + Member: TPasElement; + MemberResolved: TPasResolverResult; + Prop: TPasProperty; + ProcType: TPasProcedureType; +begin + {$IFDEF VerbosePasAnalyzer} + writeln('TPasAnalyzer.UsePublished START ',GetObjName(El)); + {$ENDIF} + if ElementVisited(El,paumPublished) then exit; + C:=El.ClassType; + if C=TPasUnresolvedSymbolRef then + else if (C=TPasVariable) or (C=TPasConst) then + UsePublished(TPasVariable(El).VarType) + else if C=TPasProperty then + begin + // published property + Prop:=TPasProperty(El); + for i:=0 to Prop.Args.Count-1 do + UsePublished(TPasArgument(Prop.Args[i]).ArgType); + UsePublished(Prop.VarType); + // Note: read, write and index don't need extra typeinfo + + // stored and defaultvalue are only used when published -> mark as used + UseElement(Prop.StoredAccessor,rraRead,false); + UseElement(Prop.DefaultExpr,rraRead,false); + end + else if (C=TPasAliasType) or (C=TPasTypeAliasType) then + UsePublished(TPasAliasType(El).DestType) + else if C=TPasSetType then + UsePublished(TPasSetType(El).EnumType) + else if C=TPasArrayType then + begin + UsePublished(TPasArrayType(El).ElType); + for i:=0 to length(TPasArrayType(El).Ranges)-1 do + begin + Member:=TPasArrayType(El).Ranges[i]; + Resolver.ComputeElement(Member,MemberResolved,[rcConstant]); + UsePublished(MemberResolved.TypeEl); + end; + end + else if C=TPasPointerType then + UsePublished(TPasPointerType(El).DestType) + else if C=TPasClassType then + else if C=TPasClassOfType then + else if C=TPasRecordType then + begin + // published record: use all members + Members:=TPasRecordType(El).Members; + for i:=0 to Members.Count-1 do + begin + UsePublished(TPasElement(Members[i])); + UseElement(Member,rraNone,true); + end; + end + else if C.InheritsFrom(TPasProcedure) then + UsePublished(TPasProcedure(El).ProcType) + else if C.InheritsFrom(TPasProcedureType) then + begin + ProcType:=TPasProcedureType(El); + for i:=0 to ProcType.Args.Count-1 do + UsePublished(TPasArgument(ProcType.Args[i]).ArgType); + if El is TPasFunctionType then + UsePublished(TPasFunctionType(El).ResultEl.ResultType); + end + else + RaiseNotSupported(20170414153904,El); +end; + procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode); procedure UseInitFinal(aSection: TPasImplBlock); @@ -1158,7 +1234,7 @@ procedure TPasAnalyzer.UseClassType(El: TPasClassType; Mode: TPAUseMode); var i: Integer; Member: TPasElement; - UsePublished, FirstTime: Boolean; + AllPublished, FirstTime: Boolean; ProcScope: TPasProcedureScope; ClassScope: TPasClassScope; Ref: TResolvedReference; @@ -1178,6 +1254,8 @@ begin end; paumElement: if not MarkElementAsUsed(El) then exit; + else + RaiseInconsistency(20170414152143,IntToStr(ord(Mode))); end; {$IFDEF VerbosePasAnalyzer} writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime); @@ -1199,7 +1277,7 @@ begin UseType(TPasType(El.Interfaces[i]),paumElement); end; // members - UsePublished:=(Mode<>paumAllExports) and (paoKeepPublished in Options); + AllPublished:=(Mode<>paumAllExports); for i:=0 to El.Members.Count-1 do begin Member:=TPasElement(El.Members[i]); @@ -1209,10 +1287,11 @@ begin if ProcScope.OverriddenProc<>nil then AddOverride(ProcScope.OverriddenProc,Member); end; - if UsePublished and (Member.Visibility=visPublished) then + if AllPublished and (Member.Visibility=visPublished) then begin // include published if not FirstTime then continue; + UsePublished(Member); end else if Mode=paumElement then continue @@ -1763,6 +1842,11 @@ begin Result:=FindElement(El)<>nil; end; +function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean; +begin + Result:=FChecked[paumPublished].Find(El)<>nil; +end; + function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean; begin if El=nil then @@ -1772,7 +1856,7 @@ begin if IsExport(El) then exit(false); case El.Visibility of visPrivate,visStrictPrivate: exit(true); - visPublished: if paoKeepPublished in Options then exit(false); + visPublished: exit(false); end; Result:=IsModuleInternal(El.Parent); end;