pasuseanalyzer.pas 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905
  1. {
  2. This file is part of the Free Component Library
  3. Pascal parse tree classes
  4. Copyright (c) 2017 Mattias Gaertner, [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {
  12. Abstract:
  13. After running TPasResolver, run this to
  14. - create a list of used declararion, either in a module or a whole program.
  15. - emit hints about unused declarations
  16. - and warnings about uninitialized variables.
  17. Working:
  18. - mark used elements of a module, starting from all accessible elements
  19. - Hint: 'Unit "%s" not used in %s'
  20. - Hint: 'Parameter "%s" not used'
  21. - Hint: 'Local variable "%s" not used'
  22. - Hint: 'Value parameter "%s" is assigned but never used'
  23. - Hint: 'Local variable "%s" is assigned but never used'
  24. - Hint: 'Local %s "%s" not used'
  25. - Hint: 'Private field "%s" is never used'
  26. - Hint: 'Private field "%s" is assigned but never used'
  27. - Hint: 'Private method "%s" is never used'
  28. - Hint: 'Private type "%s" never used'
  29. - Hint: 'Private const "%s" never used'
  30. - Hint: 'Private property "%s" never used'
  31. - Hint: 'Function result does not seem to be set'
  32. - TPasArgument: compute the effective Access
  33. - calls: use the effective Access of arguments
  34. }
  35. unit PasUseAnalyzer;
  36. {$mode objfpc}{$H+}
  37. {$inline on}
  38. {$ifdef fpc}
  39. {$define UsePChar}
  40. {$define HasInt64}
  41. {$endif}
  42. interface
  43. uses
  44. {$ifdef pas2js}
  45. js,
  46. {$else}
  47. AVL_Tree,
  48. {$endif}
  49. Classes, SysUtils, Types,
  50. PasTree, PScanner, PasResolveEval, PasResolver;
  51. const
  52. // non fpc hints
  53. nPAParameterInOverrideNotUsed = 4501;
  54. sPAParameterInOverrideNotUsed = 'Parameter "%s" not used';
  55. // fpc hints: use same IDs as fpc
  56. nPAUnitNotUsed = 5023;
  57. sPAUnitNotUsed = 'Unit "%s" not used in %s';
  58. nPAParameterNotUsed = 5024;
  59. sPAParameterNotUsed = 'Parameter "%s" not used';
  60. nPALocalVariableNotUsed = 5025;
  61. sPALocalVariableNotUsed = 'Local variable "%s" not used';
  62. nPAValueParameterIsAssignedButNeverUsed = 5026;
  63. sPAValueParameterIsAssignedButNeverUsed = 'Value parameter "%s" is assigned but never used';
  64. nPALocalVariableIsAssignedButNeverUsed = 5027;
  65. sPALocalVariableIsAssignedButNeverUsed = 'Local variable "%s" is assigned but never used';
  66. nPALocalXYNotUsed = 5028;
  67. sPALocalXYNotUsed = 'Local %s "%s" not used';
  68. nPAPrivateFieldIsNeverUsed = 5029;
  69. sPAPrivateFieldIsNeverUsed = 'Private field "%s" is never used';
  70. nPAPrivateFieldIsAssignedButNeverUsed = 5030;
  71. sPAPrivateFieldIsAssignedButNeverUsed = 'Private field "%s" is assigned but never used';
  72. nPAPrivateMethodIsNeverUsed = 5031;
  73. sPAPrivateMethodIsNeverUsed = 'Private method "%s" is never used';
  74. nPAFunctionResultDoesNotSeemToBeSet = 5033;
  75. sPAFunctionResultDoesNotSeemToBeSet = 'Function result does not seem to be set';
  76. nPAPrivateTypeXNeverUsed = 5071;
  77. sPAPrivateTypeXNeverUsed = 'Private type "%s" never used';
  78. nPAPrivateConstXNeverUsed = 5072;
  79. sPAPrivateConstXNeverUsed = 'Private const "%s" never used';
  80. nPAPrivatePropertyXNeverUsed = 5073;
  81. sPAPrivatePropertyXNeverUsed = 'Private property "%s" never used';
  82. type
  83. EPasAnalyzer = class(EPasResolve);
  84. { TPAMessage }
  85. TPAMessage = class
  86. private
  87. FRefCount: integer;
  88. public
  89. Id: TMaxPrecInt;
  90. MsgType: TMessageType;
  91. MsgNumber: integer;
  92. MsgText: string;
  93. MsgPattern: String;
  94. Args: TMessageArgs;
  95. PosEl: TPasElement;
  96. Filename: string;
  97. Row, Col: integer;
  98. constructor Create;
  99. procedure AddRef;
  100. procedure Release;
  101. property RefCount: integer read FRefCount;
  102. end;
  103. TPAMessageEvent = procedure(Sender: TObject; Msg: TPAMessage) of object;
  104. TPAIdentifierAccess = (
  105. paiaNone,
  106. paiaRead,
  107. paiaWrite,
  108. paiaReadWrite,
  109. paiaWriteRead
  110. );
  111. { TPAElement }
  112. TPAElement = class
  113. private
  114. FElement: TPasElement;
  115. procedure SetElement(AValue: TPasElement);
  116. public
  117. Access: TPAIdentifierAccess;
  118. destructor Destroy; override;
  119. property Element: TPasElement read FElement write SetElement;
  120. end;
  121. TPAElementClass = class of TPAElement;
  122. { TPAOverrideList
  123. used for
  124. - a method and its overrides
  125. - an interface method and its implementations
  126. - an interface and its delegations (property implements) }
  127. TPAOverrideList = class
  128. private
  129. FElement: TPasElement;
  130. FOverrides: TFPList; // list of TPasElement
  131. function GetOverrides(Index: integer): TPasElement; inline;
  132. procedure SetElement(AValue: TPasElement);
  133. public
  134. constructor Create;
  135. destructor Destroy; override;
  136. procedure Add(OverrideEl: TPasElement);
  137. property Element: TPasElement read FElement write SetElement;
  138. function Count: integer;
  139. function IndexOf(OverrideEl: TPasElement): integer; inline;
  140. property Overrides[Index: integer]: TPasElement read GetOverrides; default;
  141. end;
  142. {$ifdef pas2js}
  143. TPASItemToNameProc = function(Item: Pointer): String;
  144. {$endif}
  145. { TPasAnalyzerKeySet - set of items, each item has a key, no duplicate keys }
  146. TPasAnalyzerKeySet = class
  147. private
  148. {$ifdef pas2js}
  149. FItems: TJSObject;
  150. FCount: integer;
  151. FItemToName: TPASItemToNameProc;
  152. FKeyToName: TPASItemToNameProc;
  153. {$else}
  154. FTree: TAVLTree; // tree of pointers, sorted for keys given by OnItemToKey, no duplicate keys
  155. FCompareKeyWithData: TListSortCompare;
  156. {$endif}
  157. public
  158. {$ifdef pas2js}
  159. constructor Create(const OnItemToName, OnKeyToName: TPASItemToNameProc); reintroduce;
  160. {$else}
  161. constructor Create(const OnCompareMethod: TListSortCompare;
  162. const OnCompareKeyWithData: TListSortCompare);
  163. {$endif}
  164. destructor Destroy; override;
  165. procedure Clear;
  166. procedure FreeItems;
  167. procedure Add(Item: Pointer; CheckDuplicates: boolean = true);
  168. procedure Remove(Item: Pointer);
  169. function ContainsItem(Item: Pointer): boolean;
  170. function ContainsKey(Key: Pointer): boolean;
  171. function FindItem(Item: Pointer): Pointer;
  172. function FindKey(Key: Pointer): Pointer;
  173. function Count: integer;
  174. function GetList: TFPList; // list of items
  175. end;
  176. TPasAnalyzerOption = (
  177. paoOnlyExports, // default: use all class members accessible from outside (protected, but not private)
  178. paoImplReferences // collect references of top lvl proc implementations, initializationa dn finalization sections
  179. );
  180. TPasAnalyzerOptions = set of TPasAnalyzerOption;
  181. TPAUseMode = (
  182. paumElement, // Mark element. Do not descend into children.
  183. paumAllPasUsable, // Mark element and descend into children and mark non private identifiers
  184. paumAllExports, // Do not mark element. Descend into children and mark exports.
  185. paumTypeInfo // Mark element and its type and descend into children and mark published identifiers
  186. );
  187. TPAUseModes = set of TPAUseMode;
  188. const
  189. PAUseModeToPSRefAccess: array[TPAUseMode] of TPSRefAccess = (
  190. psraRead,
  191. psraRead,
  192. psraRead,
  193. psraTypeInfo
  194. );
  195. type
  196. { TPasAnalyzer }
  197. TPasAnalyzer = class
  198. private
  199. FChecked: array[TPAUseMode] of TPasAnalyzerKeySet; // tree of TElement
  200. FOnMessage: TPAMessageEvent;
  201. FOptions: TPasAnalyzerOptions;
  202. FOverrideLists: TPasAnalyzerKeySet; // tree of TPAOverrideList sorted for Element
  203. FResolver: TPasResolver;
  204. FScopeModule: TPasModule;
  205. FUsedElements: TPasAnalyzerKeySet; // tree of TPAElement sorted for Element
  206. procedure UseElType(El: TPasElement; aType: TPasType; Mode: TPAUseMode); inline;
  207. function AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
  208. procedure SetOptions(AValue: TPasAnalyzerOptions);
  209. procedure UpdateAccess(IsWrite: Boolean; IsRead: Boolean; Usage: TPAElement);
  210. procedure OnUseScopeRef(Data, DeclScope: pointer);
  211. protected
  212. procedure RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
  213. procedure RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement; const Msg: string = '');
  214. function FindTopImplScope(El: TPasElement): TPasScope;
  215. // mark used elements
  216. function Add(El: TPasElement; CheckDuplicate: boolean = true;
  217. aClass: TPAElementClass = nil): TPAElement;
  218. function PAElementExists(El: TPasElement): boolean; inline;
  219. procedure CreateTree; virtual;
  220. function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
  221. function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
  222. procedure MarkImplScopeRef(El, RefEl: TPasElement; Access: TPSRefAccess);
  223. procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
  224. UseFull: boolean); virtual;
  225. procedure UseTypeInfo(El: TPasElement); virtual;
  226. procedure UseModule(aModule: TPasModule; Mode: TPAUseMode); virtual;
  227. procedure UseSection(Section: TPasSection; Mode: TPAUseMode); virtual;
  228. procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
  229. procedure UseImplElement(El: TPasImplElement); virtual;
  230. procedure UseExpr(El: TPasExpr); virtual;
  231. procedure UseExprRef(El: TPasElement; Expr: TPasExpr;
  232. Access: TResolvedRefAccess; UseFull: boolean); virtual;
  233. procedure UseInheritedExpr(El: TInheritedExpr); virtual;
  234. procedure UseScopeReferences(Refs: TPasScopeReferences); virtual;
  235. procedure UseProcedure(Proc: TPasProcedure); virtual;
  236. procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
  237. procedure UseType(El: TPasType; Mode: TPAUseMode); virtual;
  238. procedure UseClassOrRecType(El: TPasMembersType; Mode: TPAUseMode); virtual;
  239. procedure UseVariable(El: TPasVariable; Access: TResolvedRefAccess;
  240. UseFull: boolean); virtual;
  241. procedure UseResourcestring(El: TPasResString); virtual;
  242. procedure UseArgument(El: TPasArgument; Access: TResolvedRefAccess); virtual;
  243. procedure UseResultElement(El: TPasResultElement; Access: TResolvedRefAccess); virtual;
  244. // create hints for a unit, program or library
  245. procedure EmitElementHints(El: TPasElement); virtual;
  246. procedure EmitSectionHints(Section: TPasSection); virtual;
  247. procedure EmitDeclarationsHints(El: TPasDeclarations); virtual;
  248. procedure EmitTypeHints(El: TPasType); virtual;
  249. procedure EmitVariableHints(El: TPasVariable); virtual;
  250. procedure EmitProcedureHints(El: TPasProcedure); virtual;
  251. public
  252. constructor Create;
  253. destructor Destroy; override;
  254. procedure Clear;
  255. procedure AnalyzeModule(aModule: TPasModule);
  256. procedure AnalyzeWholeProgram(aStartModule: TPasProgram);
  257. procedure EmitModuleHints(aModule: TPasModule); virtual;
  258. function FindElement(El: TPasElement): TPAElement; inline;
  259. function FindUsedElement(El: TPasElement): TPAElement;
  260. // utility
  261. function IsUsed(El: TPasElement): boolean; // valid after calling Analyze*
  262. function IsTypeInfoUsed(El: TPasElement): boolean; // valid after calling Analyze*
  263. function IsModuleInternal(El: TPasElement): boolean;
  264. function IsExport(El: TPasElement): boolean;
  265. function IsIdentifier(El: TPasElement): boolean;
  266. function IsImplBlockEmpty(El: TPasImplBlock): boolean;
  267. procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
  268. MsgNumber: integer; Fmt: String;
  269. const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
  270. PosEl: TPasElement);
  271. procedure EmitMessage(Msg: TPAMessage);
  272. class function GetWarnIdentifierNumbers(Identifier: string;
  273. out MsgNumbers: TIntegerDynArray): boolean; virtual;
  274. function GetUsedElements: TFPList; virtual; // list of TPAElement
  275. property OnMessage: TPAMessageEvent read FOnMessage write FOnMessage;
  276. property Options: TPasAnalyzerOptions read FOptions write SetOptions;
  277. property Resolver: TPasResolver read FResolver write FResolver;
  278. property ScopeModule: TPasModule read FScopeModule write FScopeModule;
  279. end;
  280. {$ifdef pas2js}
  281. function PasElementToHashName(Item: Pointer): String;
  282. function PAElement_ElToHashName(Item: Pointer): String;
  283. function PAOverrideList_ElToHashName(Item: Pointer): String;
  284. {$else}
  285. function ComparePAElements(Identifier1, Identifier2: Pointer): integer;
  286. function CompareElementWithPAElement(El, Id: Pointer): integer;
  287. function ComparePAOverrideLists(List1, List2: Pointer): integer;
  288. function CompareElementWithPAOverrideList(El, List: Pointer): integer;
  289. {$endif}
  290. function GetElModName(El: TPasElement): string;
  291. function dbgs(a: TPAIdentifierAccess): string; overload;
  292. implementation
  293. {$ifdef pas2js}
  294. function PasElementToHashName(Item: Pointer): String;
  295. var
  296. El: TPasElement absolute Item;
  297. begin
  298. Result:=string(jsvalue(El.PasElementId));
  299. end;
  300. function PAElement_ElToHashName(Item: Pointer): String;
  301. var
  302. El: TPAElement absolute Item;
  303. begin
  304. Result:=string(jsvalue(El.Element.PasElementId));
  305. end;
  306. function PAOverrideList_ElToHashName(Item: Pointer): String;
  307. var
  308. List: TPAOverrideList absolute Item;
  309. begin
  310. Result:=string(jsvalue(List.Element.PasElementId));
  311. end;
  312. {$else}
  313. function ComparePointer(Data1, Data2: Pointer): integer;
  314. begin
  315. if Data1>Data2 then Result:=-1
  316. else if Data1<Data2 then Result:=1
  317. else Result:=0;
  318. end;
  319. function ComparePAElements(Identifier1, Identifier2: Pointer): integer;
  320. var
  321. Item1: TPAElement absolute Identifier1;
  322. Item2: TPAElement absolute Identifier2;
  323. begin
  324. Result:=ComparePointer(Item1.Element,Item2.Element);
  325. end;
  326. function CompareElementWithPAElement(El, Id: Pointer): integer;
  327. var
  328. Identifier: TPAElement absolute Id;
  329. begin
  330. Result:=ComparePointer(El,Identifier.Element);
  331. end;
  332. function ComparePAOverrideLists(List1, List2: Pointer): integer;
  333. var
  334. Item1: TPAOverrideList absolute List1;
  335. Item2: TPAOverrideList absolute List2;
  336. begin
  337. Result:=ComparePointer(Item1.Element,Item2.Element);
  338. end;
  339. function CompareElementWithPAOverrideList(El, List: Pointer): integer;
  340. var
  341. OvList: TPAOverrideList absolute List;
  342. begin
  343. Result:=ComparePointer(El,OvList.Element);
  344. end;
  345. {$endif}
  346. function GetElModName(El: TPasElement): string;
  347. var
  348. aModule: TPasModule;
  349. begin
  350. if El=nil then exit('nil');
  351. Result:=El.PathName+':'+El.ClassName;
  352. aModule:=El.GetModule;
  353. if aModule=El then exit;
  354. if aModule=nil then
  355. Result:='NilModule.'+Result;
  356. end;
  357. function dbgs(a: TPAIdentifierAccess): string;
  358. begin
  359. str(a,Result);
  360. end;
  361. { TPasAnalyzerKeySet }
  362. {$ifdef pas2js}
  363. constructor TPasAnalyzerKeySet.Create(const OnItemToName,
  364. OnKeyToName: TPASItemToNameProc);
  365. begin
  366. FItemToName:=OnItemToName;
  367. FKeyToName:=OnKeyToName;
  368. FItems:=TJSObject.new;
  369. end;
  370. {$else}
  371. constructor TPasAnalyzerKeySet.Create(const OnCompareMethod: TListSortCompare;
  372. const OnCompareKeyWithData: TListSortCompare);
  373. begin
  374. FTree:=TAVLTree.Create(OnCompareMethod);
  375. FCompareKeyWithData:=OnCompareKeyWithData;
  376. end;
  377. {$endif}
  378. destructor TPasAnalyzerKeySet.Destroy;
  379. begin
  380. {$ifdef pas2js}
  381. FItems:=nil;
  382. {$else}
  383. FreeAndNil(FTree);
  384. {$endif}
  385. inherited Destroy;
  386. end;
  387. procedure TPasAnalyzerKeySet.Clear;
  388. begin
  389. {$ifdef pas2js}
  390. FItems:=TJSObject.new;
  391. FCount:=0;
  392. {$else}
  393. FTree.Clear;
  394. {$endif}
  395. end;
  396. procedure TPasAnalyzerKeySet.FreeItems;
  397. {$ifdef pas2js}
  398. var
  399. List: TStringDynArray;
  400. i: Integer;
  401. begin
  402. List:=TJSObject.getOwnPropertyNames(FItems);
  403. for i:=0 to length(List)-1 do
  404. TObject(FItems[List[i]]).Destroy;
  405. FItems:=TJSObject.new;
  406. FCount:=0;
  407. end;
  408. {$else}
  409. begin
  410. FTree.FreeAndClear;
  411. end;
  412. {$endif}
  413. procedure TPasAnalyzerKeySet.Add(Item: Pointer; CheckDuplicates: boolean);
  414. begin
  415. if CheckDuplicates {$IFDEF VerbosePasAnalyzer}or true{$endif} then
  416. if ContainsItem(Item) then
  417. raise Exception.Create('[20181101151755] TPasAnalyzerSet.Add duplicate');
  418. {$ifdef pas2js}
  419. FItems['%'+FItemToName(Item)]:=Item;
  420. inc(FCount);
  421. {$else}
  422. FTree.Add(Item);
  423. {$endif}
  424. {$ifdef VerbosePasAnalyzer}
  425. if not ContainsItem(Item) then
  426. raise Exception.Create('[20181101151811] TPasAnalyzerSet.Add failed');
  427. {$endif}
  428. end;
  429. procedure TPasAnalyzerKeySet.Remove(Item: Pointer);
  430. {$ifdef pas2js}
  431. var
  432. aName: string;
  433. begin
  434. aName:='%'+FItemToName(Item);
  435. if not FItems.hasOwnProperty(aName) then exit;
  436. JSDelete(FItems,aName);
  437. dec(FCount);
  438. end;
  439. {$else}
  440. begin
  441. FTree.Remove(Item);
  442. end;
  443. {$endif}
  444. function TPasAnalyzerKeySet.ContainsItem(Item: Pointer): boolean;
  445. begin
  446. {$ifdef pas2js}
  447. Result:=FItems.hasOwnProperty('%'+FItemToName(Item));
  448. {$else}
  449. Result:=FTree.Find(Item)<>nil;
  450. {$endif}
  451. end;
  452. function TPasAnalyzerKeySet.ContainsKey(Key: Pointer): boolean;
  453. begin
  454. {$ifdef pas2js}
  455. Result:=FItems.hasOwnProperty('%'+FKeyToName(Key));
  456. {$else}
  457. Result:=FTree.FindKey(Key,FCompareKeyWithData)<>nil;
  458. {$endif}
  459. end;
  460. function TPasAnalyzerKeySet.FindItem(Item: Pointer): Pointer;
  461. {$ifdef pas2js}
  462. var
  463. aName: string;
  464. begin
  465. aName:='%'+FItemToName(Item);
  466. if not FItems.hasOwnProperty(aName) then
  467. exit(nil)
  468. else
  469. Result:=Pointer(FItems[aName]);
  470. end;
  471. {$else}
  472. var
  473. Node: TAVLTreeNode;
  474. begin
  475. Node:=FTree.Find(Item);
  476. if Node<>nil then
  477. Result:=Node.Data
  478. else
  479. Result:=nil;
  480. end;
  481. {$endif}
  482. function TPasAnalyzerKeySet.FindKey(Key: Pointer): Pointer;
  483. {$ifdef pas2js}
  484. var
  485. aName: string;
  486. begin
  487. aName:='%'+FKeyToName(Key);
  488. if not FItems.hasOwnProperty(aName) then
  489. exit(nil)
  490. else
  491. Result:=Pointer(FItems[aName]);
  492. end;
  493. {$else}
  494. var
  495. Node: TAVLTreeNode;
  496. begin
  497. Node:=FTree.FindKey(Key,FCompareKeyWithData);
  498. if Node<>nil then
  499. Result:=Node.Data
  500. else
  501. Result:=nil;
  502. end;
  503. {$endif}
  504. function TPasAnalyzerKeySet.Count: integer;
  505. begin
  506. {$ifdef pas2js}
  507. Result:=FCount;
  508. {$else}
  509. Result:=FTree.Count;
  510. {$endif}
  511. end;
  512. function TPasAnalyzerKeySet.GetList: TFPList;
  513. {$ifdef pas2js}
  514. var
  515. List: TStringDynArray;
  516. i: Integer;
  517. begin
  518. List:=TJSObject.getOwnPropertyNames(FItems);
  519. Result:=TFPList.Create;
  520. for i:=0 to length(List)-1 do
  521. Result.Add(FItems[List[i]]);
  522. end;
  523. {$else}
  524. var
  525. Node: TAVLTreeNode;
  526. begin
  527. Result:=TFPList.Create;
  528. Node:=FTree.FindLowest;
  529. while Node<>nil do
  530. begin
  531. Result.Add(Node.Data);
  532. Node:=FTree.FindSuccessor(Node);
  533. end;
  534. end;
  535. {$endif}
  536. { TPAMessage }
  537. constructor TPAMessage.Create;
  538. begin
  539. FRefCount:=1;
  540. end;
  541. procedure TPAMessage.AddRef;
  542. begin
  543. inc(FRefCount);
  544. end;
  545. procedure TPAMessage.Release;
  546. begin
  547. if FRefCount=0 then
  548. raise Exception.Create('');
  549. dec(FRefCount);
  550. if FRefCount=0 then
  551. {$ifdef pas2js}
  552. Destroy;
  553. {$else}
  554. Free;
  555. {$endif}
  556. end;
  557. { TPAOverrideList }
  558. // inline
  559. function TPAOverrideList.GetOverrides(Index: integer): TPasElement;
  560. begin
  561. Result:=TPasElement(FOverrides[Index]);
  562. end;
  563. // inline
  564. function TPAOverrideList.IndexOf(OverrideEl: TPasElement): integer;
  565. begin
  566. Result:=FOverrides.IndexOf(OverrideEl);
  567. end;
  568. procedure TPAOverrideList.SetElement(AValue: TPasElement);
  569. begin
  570. if FElement=AValue then Exit;
  571. if FElement<>nil then
  572. FElement.Release{$IFDEF CheckPasTreeRefCount}('TPAOverrideList.Element'){$ENDIF};
  573. FElement:=AValue;
  574. if FElement<>nil then
  575. FElement.AddRef{$IFDEF CheckPasTreeRefCount}('TPAOverrideList.Element'){$ENDIF};
  576. end;
  577. constructor TPAOverrideList.Create;
  578. begin
  579. FOverrides:=TFPList.Create;
  580. end;
  581. destructor TPAOverrideList.Destroy;
  582. var
  583. i: Integer;
  584. begin
  585. for i:=0 to FOverrides.Count-1 do
  586. TPasElement(FOverrides[i]).Release{$IFDEF CheckPasTreeRefCount}('TPAOverrideList.Overrides'){$ENDIF};
  587. FreeAndNil(FOverrides);
  588. Element:=nil;
  589. inherited Destroy;
  590. end;
  591. procedure TPAOverrideList.Add(OverrideEl: TPasElement);
  592. begin
  593. FOverrides.Add(OverrideEl);
  594. OverrideEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPAOverrideList.Overrides'){$ENDIF};
  595. end;
  596. function TPAOverrideList.Count: integer;
  597. begin
  598. Result:=FOverrides.Count;
  599. end;
  600. { TPAElement }
  601. procedure TPAElement.SetElement(AValue: TPasElement);
  602. begin
  603. if FElement=AValue then Exit;
  604. if FElement<>nil then
  605. FElement.Release{$IFDEF CheckPasTreeRefCount}('TPAElement.Element'){$ENDIF};
  606. FElement:=AValue;
  607. if FElement<>nil then
  608. FElement.AddRef{$IFDEF CheckPasTreeRefCount}('TPAElement.Element'){$ENDIF};
  609. end;
  610. destructor TPAElement.Destroy;
  611. begin
  612. Element:=nil;
  613. inherited Destroy;
  614. end;
  615. { TPasAnalyzer }
  616. // inline
  617. function TPasAnalyzer.PAElementExists(El: TPasElement): boolean;
  618. begin
  619. Result:=FUsedElements.ContainsKey(El);
  620. end;
  621. // inline
  622. procedure TPasAnalyzer.UseElType(El: TPasElement; aType: TPasType;
  623. Mode: TPAUseMode);
  624. begin
  625. if aType=nil then exit;
  626. MarkImplScopeRef(El,aType,PAUseModeToPSRefAccess[Mode]);
  627. UseType(aType,Mode);
  628. end;
  629. // inline
  630. function TPasAnalyzer.FindElement(El: TPasElement): TPAElement;
  631. begin
  632. Result:=TPAElement(FUsedElements.FindKey(El));
  633. end;
  634. procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions);
  635. begin
  636. if FOptions=AValue then Exit;
  637. FOptions:=AValue;
  638. end;
  639. function TPasAnalyzer.AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
  640. // OverrideEl overrides OverriddenEl
  641. // returns true if new override
  642. var
  643. Item: TPAOverrideList;
  644. OverriddenPAEl: TPAElement;
  645. TypeEl: TPasType;
  646. begin
  647. {$IFDEF VerbosePasAnalyzer}
  648. writeln('TPasAnalyzer.AddOverride OverriddenEl=',GetElModName(OverriddenEl),' OverrideEl=',GetElModName(OverrideEl));
  649. {$ENDIF}
  650. Item:=TPAOverrideList(FOverrideLists.FindKey(OverriddenEl));
  651. if Item=nil then
  652. begin
  653. Item:=TPAOverrideList.Create;
  654. Item.Element:=OverriddenEl;
  655. FOverrideLists.Add(Item,false);
  656. end
  657. else
  658. begin
  659. if Item.IndexOf(OverrideEl)>=0 then
  660. exit(false);
  661. end;
  662. // new override
  663. Item.Add(OverrideEl);
  664. Result:=true;
  665. OverriddenPAEl:=FindElement(OverriddenEl);
  666. if OverriddenPAEl<>nil then
  667. begin
  668. // OverriddenEl was already used -> use OverrideEl
  669. if OverrideEl.ClassType=TPasProperty then
  670. begin
  671. if OverriddenEl is TPasType then
  672. begin
  673. TypeEl:=Resolver.ResolveAliasTypeEl(TPasType(OverriddenEl));
  674. if (TypeEl.ClassType=TPasClassType)
  675. and (TPasClassType(TypeEl).ObjKind=okInterface) then
  676. begin
  677. // interface was already used -> use delegation / property implements
  678. UseVariable(TPasProperty(OverrideEl),rraRead,false);
  679. exit;
  680. end;
  681. end;
  682. RaiseNotSupported(20180328221736,OverrideEl,GetElModName(OverriddenEl));
  683. end
  684. else
  685. UseElement(OverrideEl,rraNone,true);
  686. end;
  687. end;
  688. procedure TPasAnalyzer.UpdateAccess(IsWrite: Boolean; IsRead: Boolean;
  689. Usage: TPAElement);
  690. begin
  691. if IsRead then
  692. case Usage.Access of
  693. paiaNone: Usage.Access:=paiaRead;
  694. paiaRead: ;
  695. paiaWrite: Usage.Access:=paiaWriteRead;
  696. paiaReadWrite: ;
  697. paiaWriteRead: ;
  698. else RaiseInconsistency(20170311183122, '');
  699. end;
  700. if IsWrite then
  701. case Usage.Access of
  702. paiaNone: Usage.Access:=paiaWrite;
  703. paiaRead: Usage.Access:=paiaReadWrite;
  704. paiaWrite: ;
  705. paiaReadWrite: ;
  706. paiaWriteRead: ;
  707. else RaiseInconsistency(20170311183127, '');
  708. end;
  709. end;
  710. procedure TPasAnalyzer.OnUseScopeRef(Data, DeclScope: pointer);
  711. var
  712. Ref: TPasScopeReference absolute data;
  713. Scope: TPasScope absolute DeclScope;
  714. begin
  715. if Scope=nil then ;
  716. while Ref<>nil do
  717. begin
  718. case Ref.Access of
  719. psraNone: ;
  720. psraRead: UseElement(Ref.Element,rraRead,false);
  721. psraWrite: UseElement(Ref.Element,rraAssign,false);
  722. psraReadWrite: UseElement(Ref.Element,rraReadAndAssign,false);
  723. psraWriteRead:
  724. begin
  725. UseElement(Ref.Element,rraAssign,false);
  726. UseElement(Ref.Element,rraRead,false);
  727. end;
  728. psraTypeInfo: UseTypeInfo(Ref.Element);
  729. else
  730. RaiseNotSupported(20180228191928,Ref.Element,dbgs(Ref.Access));
  731. end;
  732. Ref:=Ref.NextSameName;
  733. end;
  734. end;
  735. procedure TPasAnalyzer.RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
  736. begin
  737. {$IFDEF VerbosePasAnalyzer}
  738. writeln('TPasAnalyzer.RaiseInconsistency ['+IntToStr(Id)+']: '+Msg);
  739. {$ENDIF}
  740. raise EPasAnalyzer.Create('['+IntToStr(Id)+']: '+Msg);
  741. end;
  742. procedure TPasAnalyzer.RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement;
  743. const Msg: string);
  744. var
  745. s: String;
  746. E: EPasAnalyzer;
  747. begin
  748. s:='['+IntToStr(Id)+']: Element='+GetElModName(El);
  749. if Msg<>'' then S:=S+' '+Msg;
  750. E:=EPasAnalyzer.Create(s);
  751. E.PasElement:=El;
  752. {$IFDEF VerbosePasAnalyzer}
  753. writeln('TPasAnalyzer.RaiseNotSupported ',E.Message);
  754. {$ENDIF}
  755. raise E;
  756. end;
  757. function TPasAnalyzer.FindTopImplScope(El: TPasElement): TPasScope;
  758. var
  759. ProcScope: TPasProcedureScope;
  760. C: TClass;
  761. ImplProc: TPasProcedure;
  762. begin
  763. Result:=nil;
  764. while El<>nil do
  765. begin
  766. C:=El.ClassType;
  767. if C.InheritsFrom(TPasProcedure) then
  768. begin
  769. ProcScope:=TPasProcedureScope(El.CustomData);
  770. if ProcScope.DeclarationProc<>nil then
  771. ProcScope:=TPasProcedureScope(ProcScope.DeclarationProc.CustomData);
  772. ImplProc:=ProcScope.ImplProc;
  773. if ImplProc=nil then
  774. ImplProc:=TPasProcedure(ProcScope.Element);
  775. if ImplProc.Body<>nil then
  776. // has implementation, not an external proc
  777. Result:=ProcScope;
  778. end
  779. else if (C=TInitializationSection)
  780. or (C=TFinalizationSection) then
  781. Result:=TPasInitialFinalizationScope(El.CustomData);
  782. El:=El.Parent;
  783. end;
  784. end;
  785. function TPasAnalyzer.Add(El: TPasElement; CheckDuplicate: boolean;
  786. aClass: TPAElementClass): TPAElement;
  787. begin
  788. if El=nil then
  789. RaiseInconsistency(20170308093407,'');
  790. {$IFDEF VerbosePasAnalyzer}
  791. writeln('TPasAnalyzer.Add ',GetElModName(El),' New=',not PAElementExists(El){$IFDEF Pas2js},' ID=[',El.PasElementId,']'{$ENDIF});
  792. {$ENDIF}
  793. {$IFDEF VerbosePasAnalyzer}CheckDuplicate:=true;{$ENDIF}
  794. if CheckDuplicate and PAElementExists(El) then
  795. RaiseInconsistency(20170304201318,'');
  796. if aClass=nil then
  797. aClass:=TPAElement;
  798. Result:=aClass.Create;
  799. Result.Element:=El;
  800. FUsedElements.Add(Result);
  801. {$IFDEF VerbosePasAnalyzer}
  802. writeln('TPasAnalyzer.Add END ',GetElModName(El),' Success=',PAElementExists(El),' '{$Ifdef pas2js},El.PasElementId{$endif});
  803. {$ENDIF}
  804. end;
  805. procedure TPasAnalyzer.CreateTree;
  806. begin
  807. FUsedElements:=TPasAnalyzerKeySet.Create(
  808. {$ifdef pas2js}
  809. @PAElement_ElToHashName,@PasElementToHashName
  810. {$else}
  811. @ComparePAElements,@CompareElementWithPAElement
  812. {$endif});
  813. end;
  814. function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass
  815. ): boolean;
  816. function MarkModule(CurModule: TPasModule): boolean;
  817. begin
  818. if PAElementExists(CurModule) then
  819. exit(false);
  820. {$IFDEF VerbosePasAnalyzer}
  821. writeln('TPasAnalyzer.MarkElement.MarkModule mark "',GetElModName(CurModule),'"');
  822. {$ENDIF}
  823. Add(CurModule);
  824. Result:=true;
  825. end;
  826. var
  827. CurModule: TPasModule;
  828. begin
  829. if El=nil then exit(false);
  830. CurModule:=El.GetModule;
  831. if CurModule=nil then
  832. begin
  833. if El.ClassType=TPasUnresolvedSymbolRef then
  834. exit(false);
  835. {$IFDEF VerbosePasAnalyzer}
  836. writeln('TPasAnalyzer.MarkElement GetModule failed for El=',GetElModName(El),' El.Parent=',GetElModName(El.Parent));
  837. {$ENDIF}
  838. RaiseInconsistency(20170308093540,GetElModName(El));
  839. end;
  840. if (ScopeModule<>nil) then
  841. begin
  842. // single module analysis
  843. if (CurModule<>ScopeModule) then
  844. begin
  845. // element from another unit
  846. // -> mark unit as used and do not descend deeper
  847. MarkModule(CurModule);
  848. exit(false);
  849. end;
  850. end;
  851. // mark element
  852. if PAElementExists(El) then exit(false);
  853. Add(El,false,aClass);
  854. Result:=true;
  855. if ScopeModule=nil then
  856. begin
  857. // whole program analysis
  858. if IsIdentifier(El) then
  859. // an identifier of this unit is used -> mark unit
  860. if MarkModule(CurModule) then
  861. UseModule(CurModule,paumElement);
  862. end;
  863. end;
  864. function TPasAnalyzer.ElementVisited(El: TPasElement; Mode: TPAUseMode
  865. ): boolean;
  866. begin
  867. if El=nil then
  868. exit(true);
  869. if FChecked[Mode].ContainsItem(El) then exit(true);
  870. Result:=false;
  871. FChecked[Mode].Add(El,false);
  872. end;
  873. procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement;
  874. Access: TPSRefAccess);
  875. procedure CheckImplRef;
  876. // check if El inside a proc, initialization or finalization
  877. // and if RefEl is outside
  878. var
  879. ElImplScope, RefElImplScope: TPasScope;
  880. begin
  881. ElImplScope:=FindTopImplScope(El);
  882. if ElImplScope=nil then exit;
  883. RefElImplScope:=FindTopImplScope(RefEl);
  884. if RefElImplScope=ElImplScope then exit;
  885. if (RefEl.Name='') and not (RefEl is TInterfaceSection) then
  886. exit; // reference to anonymous type -> not needed
  887. if ElImplScope is TPasProcedureScope then
  888. TPasProcedureScope(ElImplScope).AddReference(RefEl,Access)
  889. else if ElImplScope is TPasInitialFinalizationScope then
  890. TPasInitialFinalizationScope(ElImplScope).AddReference(RefEl,Access)
  891. else
  892. RaiseInconsistency(20180302142933,GetObjName(ElImplScope));
  893. end;
  894. begin
  895. if RefEl=nil then exit;
  896. if RefEl.Parent=El then exit; // same scope
  897. if paoImplReferences in Options then
  898. CheckImplRef;
  899. end;
  900. procedure TPasAnalyzer.UseElement(El: TPasElement; Access: TResolvedRefAccess;
  901. UseFull: boolean);
  902. var
  903. C: TClass;
  904. begin
  905. if El=nil then exit;
  906. C:=El.ClassType;
  907. if C.InheritsFrom(TPasType) then
  908. UseType(TPasType(El),paumElement)
  909. else if C.InheritsFrom(TPasVariable) then
  910. UseVariable(TPasVariable(El),Access,UseFull)
  911. else if C=TPasArgument then
  912. UseArgument(TPasArgument(El),Access)
  913. else if C=TPasResultElement then
  914. UseResultElement(TPasResultElement(El),Access)
  915. else if C=TPasResString then
  916. UseResourcestring(TPasResString(El))
  917. else if C.InheritsFrom(TPasProcedure) then
  918. UseProcedure(TPasProcedure(El))
  919. else if C.InheritsFrom(TPasExpr) then
  920. UseExpr(TPasExpr(El))
  921. else if C=TPasEnumValue then
  922. begin
  923. UseExpr(TPasEnumValue(El).Value);
  924. repeat
  925. MarkElementAsUsed(El);
  926. El:=El.Parent;
  927. until not (El is TPasType);
  928. end
  929. else if C=TPasMethodResolution then
  930. // nothing to do
  931. else if (C.InheritsFrom(TPasModule)) or (C=TPasUsesUnit) then
  932. // e.g. unitname.identifier -> the module is used by the identifier
  933. else
  934. RaiseNotSupported(20170307090947,El);
  935. end;
  936. procedure TPasAnalyzer.UseTypeInfo(El: TPasElement);
  937. // mark typeinfo, do not mark code
  938. procedure UseSubEl(SubEl: TPasElement); inline;
  939. begin
  940. if SubEl=nil then exit;
  941. MarkImplScopeRef(El,SubEl,psraTypeInfo);
  942. UseTypeInfo(SubEl);
  943. end;
  944. var
  945. C: TClass;
  946. Members, Args: TFPList;
  947. i: Integer;
  948. Member: TPasElement;
  949. MemberResolved: TPasResolverResult;
  950. Prop: TPasProperty;
  951. ProcType: TPasProcedureType;
  952. ClassEl: TPasClassType;
  953. begin
  954. {$IFDEF VerbosePasAnalyzer}
  955. writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
  956. {$ENDIF}
  957. if ElementVisited(El,paumTypeInfo) then exit;
  958. C:=El.ClassType;
  959. if C=TPasUnresolvedSymbolRef then
  960. else if (C=TPasVariable) or (C=TPasConst) then
  961. UseSubEl(TPasVariable(El).VarType)
  962. else if (C=TPasArgument) then
  963. UseSubEl(TPasArgument(El).ArgType)
  964. else if C=TPasProperty then
  965. begin
  966. // published property
  967. Prop:=TPasProperty(El);
  968. Args:=Resolver.GetPasPropertyArgs(Prop);
  969. for i:=0 to Args.Count-1 do
  970. UseSubEl(TPasArgument(Args[i]).ArgType);
  971. UseSubEl(Resolver.GetPasPropertyType(Prop));
  972. UseElement(Resolver.GetPasPropertyGetter(Prop),rraRead,false);
  973. UseElement(Resolver.GetPasPropertySetter(Prop),rraRead,false);
  974. UseElement(Resolver.GetPasPropertyIndex(Prop),rraRead,false);
  975. // stored and defaultvalue are only used when published -> mark as used
  976. UseElement(Resolver.GetPasPropertyStoredExpr(Prop),rraRead,false);
  977. UseElement(Resolver.GetPasPropertyDefaultExpr(Prop),rraRead,false);
  978. end
  979. else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
  980. UseSubEl(TPasAliasType(El).DestType)
  981. else if C=TPasEnumType then
  982. else if C=TPasSetType then
  983. UseSubEl(TPasSetType(El).EnumType)
  984. else if C=TPasRangeType then
  985. else if C=TPasArrayType then
  986. begin
  987. UseSubEl(TPasArrayType(El).ElType);
  988. for i:=0 to length(TPasArrayType(El).Ranges)-1 do
  989. begin
  990. Member:=TPasArrayType(El).Ranges[i];
  991. Resolver.ComputeElement(Member,MemberResolved,[rcConstant]);
  992. UseSubEl(MemberResolved.HiTypeEl);
  993. end;
  994. end
  995. else if C=TPasPointerType then
  996. UseSubEl(TPasPointerType(El).DestType)
  997. else if C=TPasClassType then
  998. begin
  999. ClassEl:=TPasClassType(El);
  1000. if ClassEl.ObjKind=okInterface then
  1001. begin
  1002. // mark all used members
  1003. Members:=ClassEl.Members;
  1004. for i:=0 to Members.Count-1 do
  1005. begin
  1006. Member:=TPasElement(Members[i]);
  1007. if IsUsed(Member) then
  1008. UseTypeInfo(Member);
  1009. end;
  1010. end;
  1011. end
  1012. else if C=TPasClassOfType then
  1013. else if C=TPasRecordType then
  1014. begin
  1015. // published record: use all members
  1016. Members:=TPasRecordType(El).Members;
  1017. for i:=0 to Members.Count-1 do
  1018. begin
  1019. Member:=TPasElement(Members[i]);
  1020. UseSubEl(Member);
  1021. end;
  1022. end
  1023. else if C.InheritsFrom(TPasProcedure) then
  1024. UseSubEl(TPasProcedure(El).ProcType)
  1025. else if C.InheritsFrom(TPasProcedureType) then
  1026. begin
  1027. ProcType:=TPasProcedureType(El);
  1028. for i:=0 to ProcType.Args.Count-1 do
  1029. UseSubEl(TPasArgument(ProcType.Args[i]).ArgType);
  1030. if El is TPasFunctionType then
  1031. UseSubEl(TPasFunctionType(El).ResultEl.ResultType);
  1032. end
  1033. else
  1034. begin
  1035. {$IFDEF VerbosePasAnalyzer}
  1036. writeln('TPasAnalyzer.UsePublished ',GetObjName(El));
  1037. {$ENDIF}
  1038. RaiseNotSupported(20170414153904,El);
  1039. end;
  1040. UseElement(El,rraNone,true);
  1041. end;
  1042. procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
  1043. procedure UseInitFinal(ImplBlock: TPasImplBlock);
  1044. var
  1045. Scope: TPasInitialFinalizationScope;
  1046. begin
  1047. if ImplBlock=nil then exit;
  1048. Scope:=TPasInitialFinalizationScope(ImplBlock.CustomData);
  1049. UseScopeReferences(Scope.References);
  1050. if (Scope.References=nil) and IsImplBlockEmpty(ImplBlock) then exit;
  1051. // this module has an initialization section -> mark module
  1052. if not PAElementExists(aModule) then
  1053. Add(aModule);
  1054. UseImplBlock(ImplBlock,true);
  1055. end;
  1056. var
  1057. ModScope: TPasModuleScope;
  1058. begin
  1059. if ElementVisited(aModule,Mode) then exit;
  1060. {$IFDEF VerbosePasAnalyzer}
  1061. writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode{$IFDEF pas2js},' ',aModule.PasElementId{$ENDIF});
  1062. {$ENDIF}
  1063. if Mode in [paumAllExports,paumAllPasUsable] then
  1064. begin
  1065. if aModule is TPasProgram then
  1066. UseSection(TPasProgram(aModule).ProgramSection,Mode)
  1067. else if aModule is TPasLibrary then
  1068. UseSection(TPasLibrary(aModule).LibrarySection,Mode)
  1069. else
  1070. begin
  1071. // unit
  1072. UseSection(aModule.InterfaceSection,Mode);
  1073. // Note: implementation can not be used directly from outside
  1074. end;
  1075. end;
  1076. UseInitFinal(aModule.InitializationSection);
  1077. UseInitFinal(aModule.FinalizationSection);
  1078. ModScope:=aModule.CustomData as TPasModuleScope;
  1079. if ModScope.RangeErrorClass<>nil then
  1080. UseClassOrRecType(ModScope.RangeErrorClass,paumElement);
  1081. if ModScope.RangeErrorConstructor<>nil then
  1082. UseProcedure(ModScope.RangeErrorConstructor);
  1083. if Mode=paumElement then
  1084. // e.g. a reference: unitname.identifier
  1085. if not PAElementExists(aModule) then
  1086. Add(aModule);
  1087. end;
  1088. procedure TPasAnalyzer.UseSection(Section: TPasSection; Mode: TPAUseMode);
  1089. // called by UseModule
  1090. var
  1091. i: Integer;
  1092. UsedModule: TPasModule;
  1093. Decl: TPasElement;
  1094. OnlyExports: Boolean;
  1095. UsesClause: TPasUsesClause;
  1096. C: TClass;
  1097. begin
  1098. // Section is TProgramSection, TLibrarySection, TInterfaceSection, TImplementationSection
  1099. if Mode=paumElement then
  1100. RaiseInconsistency(20170317172721,'');
  1101. if ElementVisited(Section,Mode) then exit;
  1102. OnlyExports:=Mode=paumAllExports;
  1103. if Mode=paumAllPasUsable then
  1104. MarkElementAsUsed(Section);
  1105. {$IFDEF VerbosePasAnalyzer}
  1106. writeln('TPasAnalyzer.UseSection ',GetElModName(Section),' Mode=',Mode);
  1107. {$ENDIF}
  1108. // used units
  1109. UsesClause:=Section.UsesClause;
  1110. for i:=0 to length(UsesClause)-1 do
  1111. begin
  1112. if UsesClause[i].Module is TPasModule then
  1113. begin
  1114. UsedModule:=TPasModule(UsesClause[i].Module);
  1115. if ScopeModule=nil then
  1116. // whole program analysis
  1117. UseModule(UsedModule,paumAllExports)
  1118. else
  1119. begin
  1120. // unit analysis
  1121. if IsImplBlockEmpty(UsedModule.InitializationSection)
  1122. and IsImplBlockEmpty(UsedModule.FinalizationSection) then
  1123. continue;
  1124. if not PAElementExists(UsedModule) then
  1125. Add(UsedModule);
  1126. UseImplBlock(UsedModule.InitializationSection,true);
  1127. UseImplBlock(UsedModule.FinalizationSection,true);
  1128. end;
  1129. end;
  1130. end;
  1131. // section declarations
  1132. for i:=0 to Section.Declarations.Count-1 do
  1133. begin
  1134. Decl:=TPasElement(Section.Declarations[i]);
  1135. {$IFDEF VerbosePasAnalyzer}
  1136. writeln('TPasAnalyzer.UseSection ',Section.ClassName,' Decl=',GetElModName(Decl),' Mode=',Mode);
  1137. {$ENDIF}
  1138. C:=Decl.ClassType;
  1139. // Note: no MarkImplScopeRef needed, because all Decl are in the same scope
  1140. if C.InheritsFrom(TPasProcedure) then
  1141. begin
  1142. if OnlyExports and ([pmExport,pmPublic]*TPasProcedure(Decl).Modifiers=[]) then
  1143. continue;
  1144. UseProcedure(TPasProcedure(Decl))
  1145. end
  1146. else if C.InheritsFrom(TPasType) then
  1147. UseType(TPasType(Decl),Mode)
  1148. else if C.InheritsFrom(TPasVariable) then
  1149. begin
  1150. if OnlyExports and ([vmExport,vmPublic]*TPasVariable(Decl).VarModifiers=[]) then
  1151. continue;
  1152. UseVariable(TPasVariable(Decl),rraNone,true);
  1153. end
  1154. else if C=TPasResString then
  1155. UseResourcestring(TPasResString(Decl))
  1156. else
  1157. RaiseNotSupported(20170306165213,Decl);
  1158. end;
  1159. end;
  1160. procedure TPasAnalyzer.UseImplBlock(Block: TPasImplBlock; Mark: boolean);
  1161. var
  1162. i: Integer;
  1163. El: TPasElement;
  1164. begin
  1165. if Block=nil then exit;
  1166. if Mark and not MarkElementAsUsed(Block) then exit;
  1167. {$IFDEF VerbosePasAnalyzer}
  1168. writeln('TPasAnalyzer.UseImplBlock ',GetElModName(Block),' Elements=',Block.Elements.Count);
  1169. {$ENDIF}
  1170. for i:=0 to Block.Elements.Count-1 do
  1171. begin
  1172. El:=TPasElement(Block.Elements[i]);
  1173. if El is TPasImplElement then
  1174. UseImplElement(TPasImplElement(El))
  1175. else
  1176. RaiseNotSupported(20170306195110,El);
  1177. end;
  1178. end;
  1179. procedure TPasAnalyzer.UseImplElement(El: TPasImplElement);
  1180. var
  1181. C: TClass;
  1182. ForLoop: TPasImplForLoop;
  1183. CaseOf: TPasImplCaseOf;
  1184. i, j: Integer;
  1185. CaseSt: TPasImplCaseStatement;
  1186. WithDo: TPasImplWithDo;
  1187. SubEl, ParentEl: TPasElement;
  1188. ForScope: TPasForLoopScope;
  1189. begin
  1190. // do not mark
  1191. if El=nil then exit;
  1192. C:=El.ClassType;
  1193. if C=TPasImplBlock then
  1194. // impl block
  1195. UseImplBlock(TPasImplBlock(El),false)
  1196. else if C=TPasImplSimple then
  1197. // simple expression
  1198. UseExpr(TPasImplSimple(El).expr)
  1199. else if C=TPasImplAssign then
  1200. // a:=b
  1201. begin
  1202. UseExpr(TPasImplAssign(El).left);
  1203. UseExpr(TPasImplAssign(El).right);
  1204. end
  1205. else if C=TPasImplAsmStatement then
  1206. // asm..end
  1207. else if C=TPasImplBeginBlock then
  1208. // begin..end
  1209. UseImplBlock(TPasImplBeginBlock(El),false)
  1210. else if C=TPasImplCaseOf then
  1211. begin
  1212. // case-of
  1213. CaseOf:=TPasImplCaseOf(El);
  1214. UseExpr(CaseOf.CaseExpr);
  1215. for i:=0 to CaseOf.Elements.Count-1 do
  1216. begin
  1217. SubEl:=TPasElement(CaseOf.Elements[i]);
  1218. if SubEl.ClassType=TPasImplCaseStatement then
  1219. begin
  1220. CaseSt:=TPasImplCaseStatement(SubEl);
  1221. for j:=0 to CaseSt.Expressions.Count-1 do
  1222. UseExpr(TObject(CaseSt.Expressions[j]) as TPasExpr);
  1223. UseImplElement(CaseSt.Body);
  1224. end
  1225. else if SubEl.ClassType=TPasImplCaseElse then
  1226. UseImplBlock(TPasImplCaseElse(SubEl),false)
  1227. else
  1228. RaiseNotSupported(20170307195329,SubEl);
  1229. end;
  1230. end
  1231. else if C=TPasImplForLoop then
  1232. begin
  1233. // for-loop
  1234. ForLoop:=TPasImplForLoop(El);
  1235. UseExpr(ForLoop.VariableName);
  1236. UseExpr(ForLoop.StartExpr);
  1237. UseExpr(ForLoop.EndExpr);
  1238. ForScope:=ForLoop.CustomData as TPasForLoopScope;
  1239. MarkImplScopeRef(ForLoop,ForScope.GetEnumerator,psraRead);
  1240. UseProcedure(ForScope.GetEnumerator);
  1241. MarkImplScopeRef(ForLoop,ForScope.MoveNext,psraRead);
  1242. UseProcedure(ForScope.MoveNext);
  1243. MarkImplScopeRef(ForLoop,ForScope.Current,psraRead);
  1244. UseVariable(ForScope.Current,rraRead,false);
  1245. UseImplElement(ForLoop.Body);
  1246. end
  1247. else if C=TPasImplIfElse then
  1248. begin
  1249. // if-then-else
  1250. UseExpr(TPasImplIfElse(El).ConditionExpr);
  1251. UseImplElement(TPasImplIfElse(El).IfBranch);
  1252. UseImplElement(TPasImplIfElse(El).ElseBranch);
  1253. end
  1254. else if C=TPasImplCommand then
  1255. // used for if-then <empty> -> nothing to do
  1256. else if C=TPasImplLabelMark then
  1257. // label mark
  1258. else if C=TPasImplRepeatUntil then
  1259. begin
  1260. // repeat-until
  1261. UseImplBlock(TPasImplRepeatUntil(El),false);
  1262. UseExpr(TPasImplRepeatUntil(El).ConditionExpr);
  1263. end
  1264. else if C=TPasImplWhileDo then
  1265. begin
  1266. // while-do
  1267. UseExpr(TPasImplWhileDo(El).ConditionExpr);
  1268. UseImplBlock(TPasImplWhileDo(El),false);
  1269. end
  1270. else if C=TPasImplWithDo then
  1271. begin
  1272. // with-do
  1273. WithDo:=TPasImplWithDo(El);
  1274. for i:=0 to WithDo.Expressions.Count-1 do
  1275. UseExpr(TObject(WithDo.Expressions[i]) as TPasExpr);
  1276. UseImplBlock(WithDo,false);
  1277. end
  1278. else if C=TPasImplExceptOn then
  1279. begin
  1280. // except-on
  1281. // Note: VarEl is marked when actually used
  1282. UseElType(El,TPasImplExceptOn(El).TypeEl,paumElement);
  1283. UseImplElement(TPasImplExceptOn(El).Body);
  1284. end
  1285. else if C=TPasImplRaise then
  1286. begin
  1287. // raise
  1288. if TPasImplRaise(El).ExceptObject<>nil then
  1289. UseExpr(TPasImplRaise(El).ExceptObject)
  1290. else
  1291. begin
  1292. // raise; -> mark On E:
  1293. ParentEl:=El.Parent;
  1294. while ParentEl<>nil do
  1295. begin
  1296. if ParentEl is TPasImplExceptOn then
  1297. begin
  1298. UseVariable(TPasVariable(TPasImplExceptOn(ParentEl).VarEl),rraRead,false);
  1299. break;
  1300. end;
  1301. ParentEl:=ParentEl.Parent;
  1302. end;
  1303. end;
  1304. UseExpr(TPasImplRaise(El).ExceptAddr);
  1305. end
  1306. else if C=TPasImplTry then
  1307. begin
  1308. // try..finally/except..else..end
  1309. UseImplBlock(TPasImplTry(El),false);
  1310. UseImplBlock(TPasImplTry(El).FinallyExcept,false);
  1311. UseImplBlock(TPasImplTry(El).ElseBranch,false);
  1312. end
  1313. else
  1314. RaiseNotSupported(20170307162715,El);
  1315. end;
  1316. procedure TPasAnalyzer.UseExpr(El: TPasExpr);
  1317. var
  1318. Ref: TResolvedReference;
  1319. C: TClass;
  1320. Params: TPasExprArray;
  1321. i: Integer;
  1322. BuiltInProc: TResElDataBuiltInProc;
  1323. ParamResolved: TPasResolverResult;
  1324. Decl: TPasElement;
  1325. ModScope: TPasModuleScope;
  1326. Access: TResolvedRefAccess;
  1327. SubEl: TPasElement;
  1328. begin
  1329. if El=nil then exit;
  1330. // Note: expression itself is not marked, but it can reference identifiers
  1331. Ref:=nil;
  1332. if El.CustomData is TResolvedReference then
  1333. begin
  1334. // this is a reference -> mark target
  1335. Ref:=TResolvedReference(El.CustomData);
  1336. Decl:=Ref.Declaration;
  1337. Access:=Ref.Access;
  1338. MarkImplScopeRef(El,Decl,ResolvedToPSRefAccess[Access]);
  1339. UseElement(Decl,Access,false);
  1340. if Resolver.IsNameExpr(El) then
  1341. begin
  1342. if Ref.WithExprScope<>nil then
  1343. begin
  1344. if Ref.WithExprScope.ClassRecScope is TPasRecordScope then
  1345. begin
  1346. // a record member was accessed -> access the record too
  1347. UseExprRef(El,Ref.WithExprScope.Expr,Access,false);
  1348. exit;
  1349. end;
  1350. end;
  1351. if (Decl is TPasVariable)
  1352. and (El.Parent is TBinaryExpr)
  1353. and (TBinaryExpr(El.Parent).right=El) then
  1354. begin
  1355. if ((Decl.Parent is TPasRecordType)
  1356. or (Decl.Parent is TPasVariant)) then
  1357. begin
  1358. // a record member was accessed -> access the record with same Access
  1359. UseExprRef(El.Parent,TBinaryExpr(El.Parent).left,Access,false);
  1360. end;
  1361. end;
  1362. end;
  1363. if Decl is TPasUnresolvedSymbolRef then
  1364. begin
  1365. if Decl.CustomData is TResElDataBuiltInProc then
  1366. begin
  1367. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  1368. case BuiltInProc.BuiltIn of
  1369. bfExit:
  1370. begin
  1371. if El.Parent is TParamsExpr then
  1372. begin
  1373. Params:=(El.Parent as TParamsExpr).Params;
  1374. if length(Params)=1 then
  1375. begin
  1376. SubEl:=El.Parent;
  1377. while (SubEl<>nil) and not (SubEl is TPasProcedure) do
  1378. SubEl:=SubEl.Parent;
  1379. if (SubEl is TPasProcedure)
  1380. and (TPasProcedure(SubEl).ProcType is TPasFunctionType) then
  1381. begin
  1382. SubEl:=TPasFunctionType(TPasProcedure(SubEl).ProcType).ResultEl;
  1383. UseElement(SubEl,rraAssign,false);
  1384. end;
  1385. end;
  1386. end;
  1387. end;
  1388. bfTypeInfo:
  1389. begin
  1390. Params:=(El.Parent as TParamsExpr).Params;
  1391. if length(Params)<>1 then
  1392. RaiseNotSupported(20180226144217,El.Parent);
  1393. Resolver.ComputeElement(Params[0],ParamResolved,[rcNoImplicitProc]);
  1394. {$IFDEF VerbosePasAnalyzer}
  1395. writeln('TPasAnalyzer.UseExpr typeinfo ',GetResolverResultDbg(ParamResolved));
  1396. {$ENDIF}
  1397. if ParamResolved.IdentEl=nil then
  1398. RaiseNotSupported(20180628155107,Params[0]);
  1399. if (ParamResolved.IdentEl is TPasProcedure)
  1400. and (TPasProcedure(ParamResolved.IdentEl).ProcType is TPasFunctionType) then
  1401. begin
  1402. SubEl:=TPasFunctionType(TPasProcedure(ParamResolved.IdentEl).ProcType).ResultEl.ResultType;
  1403. MarkImplScopeRef(El,SubEl,psraTypeInfo);
  1404. UseTypeInfo(SubEl);
  1405. end
  1406. else
  1407. begin
  1408. SubEl:=ParamResolved.IdentEl;
  1409. MarkImplScopeRef(El,SubEl,psraTypeInfo);
  1410. UseTypeInfo(SubEl);
  1411. end;
  1412. // the parameter is not used otherwise
  1413. exit;
  1414. end;
  1415. bfAssert:
  1416. begin
  1417. ModScope:=Resolver.RootElement.CustomData as TPasModuleScope;
  1418. if ModScope.AssertClass<>nil then
  1419. UseElType(El,ModScope.AssertClass,paumElement);
  1420. end;
  1421. end;
  1422. end;
  1423. end;
  1424. end;
  1425. UseExpr(El.format1);
  1426. UseExpr(El.format2);
  1427. C:=El.ClassType;
  1428. if (C=TPrimitiveExpr)
  1429. or (C=TSelfExpr)
  1430. or (C=TBoolConstExpr)
  1431. or (C=TNilExpr) then
  1432. // ok
  1433. else if C=TBinaryExpr then
  1434. begin
  1435. UseExpr(TBinaryExpr(El).left);
  1436. UseExpr(TBinaryExpr(El).right);
  1437. end
  1438. else if C=TUnaryExpr then
  1439. UseExpr(TUnaryExpr(El).Operand)
  1440. else if C=TParamsExpr then
  1441. begin
  1442. UseExpr(TParamsExpr(El).Value);
  1443. Params:=TParamsExpr(El).Params;
  1444. for i:=0 to length(Params)-1 do
  1445. UseExpr(Params[i]);
  1446. end
  1447. else if C=TArrayValues then
  1448. begin
  1449. Params:=TArrayValues(El).Values;
  1450. for i:=0 to length(Params)-1 do
  1451. UseExpr(Params[i]);
  1452. end
  1453. else if C=TRecordValues then
  1454. begin
  1455. for i:=0 to length(TRecordValues(El).Fields)-1 do
  1456. UseExpr(TRecordValues(El).Fields[i].ValueExp);
  1457. end
  1458. else if C=TInheritedExpr then
  1459. UseInheritedExpr(TInheritedExpr(El))
  1460. else if C=TProcedureExpr then
  1461. UseProcedure(TProcedureExpr(El).Proc)
  1462. else
  1463. RaiseNotSupported(20170307085444,El);
  1464. end;
  1465. procedure TPasAnalyzer.UseExprRef(El: TPasElement; Expr: TPasExpr;
  1466. Access: TResolvedRefAccess; UseFull: boolean);
  1467. var
  1468. Ref: TResolvedReference;
  1469. C: TClass;
  1470. Bin: TBinaryExpr;
  1471. Params: TParamsExpr;
  1472. ValueResolved: TPasResolverResult;
  1473. Unary: TUnaryExpr;
  1474. begin
  1475. C:=Expr.ClassType;
  1476. if C=TBinaryExpr then
  1477. begin
  1478. Bin:=TBinaryExpr(Expr);
  1479. if Bin.OpCode in [eopSubIdent,eopNone] then
  1480. UseExprRef(El,Bin.right,Access,UseFull);
  1481. end
  1482. else if C=TParamsExpr then
  1483. begin
  1484. Params:=TParamsExpr(Expr);
  1485. case Params.Kind of
  1486. pekFuncParams:
  1487. if Resolver.IsTypeCast(Params) then
  1488. UseExprRef(El,Params.Params[0],Access,UseFull)
  1489. else
  1490. UseExprRef(El,Params.Value,Access,UseFull);
  1491. pekArrayParams:
  1492. begin
  1493. Resolver.ComputeElement(Params.Value,ValueResolved,[]);
  1494. if not Resolver.IsDynArray(ValueResolved.LoTypeEl) then
  1495. UseExprRef(El,Params.Value,Access,UseFull);
  1496. end;
  1497. pekSet: ;
  1498. else
  1499. RaiseNotSupported(20170403173817,Params);
  1500. end;
  1501. end
  1502. else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
  1503. begin
  1504. if (Expr.CustomData is TResolvedReference) then
  1505. begin
  1506. Ref:=TResolvedReference(Expr.CustomData);
  1507. MarkImplScopeRef(El,Ref.Declaration,ResolvedToPSRefAccess[Access]);
  1508. UseElement(Ref.Declaration,Access,UseFull);
  1509. end;
  1510. end
  1511. else if C=TUnaryExpr then
  1512. begin
  1513. Unary:=TUnaryExpr(Expr);
  1514. if Unary.OpCode in [eopAdd,eopSubtract,eopAddress,eopDeref,eopMemAddress] then
  1515. UseExprRef(El,Unary.Operand,rraRead,false)
  1516. else
  1517. RaiseNotSupported(20181015193334,Expr,OpcodeStrings[Unary.OpCode]);
  1518. end
  1519. else if (Access=rraRead)
  1520. and ((C=TPrimitiveExpr) // Kind<>pekIdent
  1521. or (C=TNilExpr)
  1522. or (C=TBoolConstExpr)
  1523. or (C=TUnaryExpr)) then
  1524. // ok
  1525. else
  1526. begin
  1527. {$IFDEF VerbosePasResolver}
  1528. writeln('TPasResolver.UseExprRef Expr=',GetObjName(Expr),' Access=',Access,' Declaration="',Expr.GetDeclaration(false),'"');
  1529. {$ENDIF}
  1530. RaiseNotSupported(20170306102159,Expr);
  1531. end;
  1532. end;
  1533. procedure TPasAnalyzer.UseInheritedExpr(El: TInheritedExpr);
  1534. var
  1535. P: TPasElement;
  1536. ProcScope: TPasProcedureScope;
  1537. Proc: TPasProcedure;
  1538. Args: TFPList;
  1539. i: Integer;
  1540. Arg: TPasArgument;
  1541. begin
  1542. if (El.Parent.ClassType=TBinaryExpr)
  1543. and (TBinaryExpr(El.Parent).OpCode=eopNone) then
  1544. // 'inherited Proc...;'
  1545. exit;
  1546. // 'inherited;'
  1547. P:=El.Parent;
  1548. while not P.InheritsFrom(TPasProcedure) do
  1549. P:=P.Parent;
  1550. ProcScope:=TPasProcedure(P).CustomData as TPasProcedureScope;
  1551. if ProcScope.DeclarationProc<>nil then
  1552. Proc:=ProcScope.DeclarationProc
  1553. else
  1554. Proc:=TPasProcedure(P);
  1555. Args:=Proc.ProcType.Args;
  1556. for i:=0 to Args.Count-1 do
  1557. begin
  1558. Arg:=TPasArgument(Args[i]);
  1559. case Arg.Access of
  1560. argDefault,argConst,argConstRef: UseArgument(Arg,rraRead);
  1561. argVar: UseArgument(Arg,rraVarParam);
  1562. argOut: UseArgument(Arg,rraOutParam);
  1563. else
  1564. RaiseNotSupported(20171107175406,Arg);
  1565. end;
  1566. end;
  1567. end;
  1568. procedure TPasAnalyzer.UseScopeReferences(Refs: TPasScopeReferences);
  1569. begin
  1570. if Refs=nil then exit;
  1571. Refs.References.ForEachCall(@OnUseScopeRef,Refs.Scope);
  1572. end;
  1573. procedure TPasAnalyzer.UseProcedure(Proc: TPasProcedure);
  1574. procedure UseOverrides(CurProc: TPasProcedure);
  1575. var
  1576. OverrideList: TPAOverrideList;
  1577. i: Integer;
  1578. OverrideProc: TPasProcedure;
  1579. begin
  1580. OverrideList:=TPAOverrideList(FOverrideLists.FindKey(CurProc));
  1581. if OverrideList=nil then exit;
  1582. // Note: while traversing the OverrideList it may grow
  1583. i:=0;
  1584. while i<OverrideList.Count do
  1585. begin
  1586. OverrideProc:=TObject(OverrideList.Overrides[i]) as TPasProcedure;
  1587. UseProcedure(OverrideProc);
  1588. inc(i);
  1589. end;
  1590. end;
  1591. var
  1592. ProcScope: TPasProcedureScope;
  1593. ImplProc: TPasProcedure;
  1594. ClassScope: TPasClassScope;
  1595. Name: String;
  1596. Identifier: TPasIdentifier;
  1597. El: TPasElement;
  1598. ClassEl: TPasClassType;
  1599. begin
  1600. if Proc=nil then exit;
  1601. // use declaration, not implementation
  1602. ProcScope:=Proc.CustomData as TPasProcedureScope;
  1603. if ProcScope.DeclarationProc<>nil then
  1604. exit; // skip implementation, Note:PasResolver always refers the declaration
  1605. if not MarkElementAsUsed(Proc) then exit;
  1606. {$IFDEF VerbosePasAnalyzer}
  1607. writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
  1608. {$ENDIF}
  1609. UseScopeReferences(ProcScope.References);
  1610. UseProcedureType(Proc.ProcType,false);
  1611. ImplProc:=Proc;
  1612. if ProcScope.ImplProc<>nil then
  1613. ImplProc:=ProcScope.ImplProc;
  1614. if ImplProc.Body<>nil then
  1615. UseImplBlock(ImplProc.Body.Body,false);
  1616. if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
  1617. AddOverride(ProcScope.OverriddenProc,Proc);
  1618. // mark overrides
  1619. if ([pmOverride,pmVirtual]*Proc.Modifiers<>[])
  1620. or ((Proc.Parent.ClassType=TPasClassType)
  1621. and (TPasClassType(Proc.Parent).ObjKind=okInterface)) then
  1622. UseOverrides(Proc);
  1623. if Proc.Parent is TPasClassType then
  1624. begin
  1625. ClassScope:=TPasClassScope(Proc.Parent.CustomData);
  1626. ClassEl:=TPasClassType(ClassScope.Element);
  1627. if (ClassEl.ObjKind=okInterface) and IsTypeInfoUsed(ClassEl) then
  1628. UseTypeInfo(Proc);
  1629. if (Proc.ClassType=TPasConstructor) or (Proc.ClassType=TPasDestructor) then
  1630. begin
  1631. if ClassScope.AncestorScope=nil then
  1632. begin
  1633. // root class constructor -> mark AfterConstruction
  1634. if Proc.ClassType=TPasConstructor then
  1635. Name:='AfterConstruction'
  1636. else
  1637. Name:='BeforeDestruction';
  1638. Identifier:=ClassScope.FindLocalIdentifier(Name);
  1639. while Identifier<>nil do
  1640. begin
  1641. El:=Identifier.Element;
  1642. if (El.ClassType=TPasProcedure)
  1643. and (TPasProcedure(El).ProcType.Args.Count=0) then
  1644. begin
  1645. UseProcedure(TPasProcedure(El));
  1646. break;
  1647. end;
  1648. Identifier:=Identifier.NextSameIdentifier;
  1649. end;
  1650. end;
  1651. end;
  1652. end;
  1653. end;
  1654. procedure TPasAnalyzer.UseProcedureType(ProcType: TPasProcedureType;
  1655. Mark: boolean);
  1656. var
  1657. i: Integer;
  1658. Arg: TPasArgument;
  1659. begin
  1660. {$IFDEF VerbosePasAnalyzer}
  1661. writeln('TPasAnalyzer.UseProcedureType ',GetElModName(ProcType));
  1662. {$ENDIF}
  1663. if Mark and not MarkElementAsUsed(ProcType) then exit;
  1664. for i:=0 to ProcType.Args.Count-1 do
  1665. begin
  1666. Arg:=TPasArgument(ProcType.Args[i]);
  1667. // Note: the arguments themselves are marked when used in code
  1668. // mark argument type and default value
  1669. UseElType(ProcType,Arg.ArgType,paumElement);
  1670. UseExpr(Arg.ValueExpr);
  1671. end;
  1672. if ProcType is TPasFunctionType then
  1673. UseElType(ProcType,TPasFunctionType(ProcType).ResultEl.ResultType,paumElement);
  1674. end;
  1675. procedure TPasAnalyzer.UseType(El: TPasType; Mode: TPAUseMode);
  1676. var
  1677. C: TClass;
  1678. i: Integer;
  1679. begin
  1680. if El=nil then exit;
  1681. C:=El.ClassType;
  1682. if Mode=paumAllExports then
  1683. begin
  1684. {$IFDEF VerbosePasAnalyzer}
  1685. writeln('TPasAnalyzer.UseType searching exports in ',GetElModName(El),' ...');
  1686. {$ENDIF}
  1687. if (C=TPasRecordType) or (C=TPasClassType) then
  1688. UseClassOrRecType(TPasMembersType(El),Mode);
  1689. end
  1690. else
  1691. begin
  1692. {$IFDEF VerbosePasAnalyzer}
  1693. writeln('TPasAnalyzer.UseType using ',GetElModName(El),' Mode=',Mode);
  1694. {$ENDIF}
  1695. if C=TPasUnresolvedSymbolRef then
  1696. begin
  1697. if (El.CustomData is TResElDataBaseType)
  1698. or (El.CustomData is TResElDataBuiltInProc) then
  1699. else
  1700. RaiseNotSupported(20170307101353,El);
  1701. end
  1702. else if (C=TPasAliasType)
  1703. or (C=TPasTypeAliasType)
  1704. or (C=TPasClassOfType) then
  1705. begin
  1706. if not MarkElementAsUsed(El) then exit;
  1707. UseElType(El,TPasAliasType(El).DestType,Mode);
  1708. if C=TPasTypeAliasType then
  1709. UseExpr(TPasTypeAliasType(El).Expr);
  1710. end
  1711. else if C=TPasArrayType then
  1712. begin
  1713. if not MarkElementAsUsed(El) then exit;
  1714. for i:=0 to length(TPasArrayType(El).Ranges)-1 do
  1715. UseExpr(TPasArrayType(El).Ranges[i]);
  1716. UseElType(El,TPasArrayType(El).ElType,Mode);
  1717. end
  1718. else if (C=TPasRecordType) or (C=TPasClassType) then
  1719. UseClassOrRecType(TPasMembersType(El),Mode)
  1720. else if C=TPasEnumType then
  1721. begin
  1722. if not MarkElementAsUsed(El) then exit;
  1723. for i:=0 to TPasEnumType(El).Values.Count-1 do
  1724. UseElement(TPasEnumValue(TPasEnumType(El).Values[i]),rraRead,false);
  1725. end
  1726. else if C=TPasPointerType then
  1727. begin
  1728. if not MarkElementAsUsed(El) then exit;
  1729. UseElType(El,TPasPointerType(El).DestType,Mode);
  1730. end
  1731. else if C=TPasRangeType then
  1732. begin
  1733. if not MarkElementAsUsed(El) then exit;
  1734. UseExpr(TPasRangeType(El).RangeExpr);
  1735. end
  1736. else if C=TPasSetType then
  1737. begin
  1738. if not MarkElementAsUsed(El) then exit;
  1739. UseElType(El,TPasSetType(El).EnumType,Mode);
  1740. end
  1741. else if C.InheritsFrom(TPasProcedureType) then
  1742. UseProcedureType(TPasProcedureType(El),true)
  1743. else
  1744. RaiseNotSupported(20170306170315,El);
  1745. if Mode=paumAllPasUsable then
  1746. UseTypeInfo(El);
  1747. end;
  1748. end;
  1749. procedure TPasAnalyzer.UseClassOrRecType(El: TPasMembersType; Mode: TPAUseMode);
  1750. // called by UseType
  1751. procedure UseDelegations;
  1752. var
  1753. OverrideList: TPAOverrideList;
  1754. i: Integer;
  1755. Prop: TPasProperty;
  1756. begin
  1757. OverrideList:=TPAOverrideList(FOverrideLists.FindKey(El));
  1758. if OverrideList=nil then exit;
  1759. // Note: while traversing the OverrideList it may grow
  1760. i:=0;
  1761. while i<OverrideList.Count do
  1762. begin
  1763. Prop:=TObject(OverrideList.Overrides[i]) as TPasProperty;
  1764. UseVariable(Prop,rraRead,false);
  1765. inc(i);
  1766. end;
  1767. end;
  1768. procedure MarkAllInterfaceImplementations(Scope: TPasClassScope);
  1769. var
  1770. i, j: Integer;
  1771. o: TObject;
  1772. Map: TPasClassIntfMap;
  1773. begin
  1774. if Scope.Interfaces=nil then exit;
  1775. for i:=0 to Scope.Interfaces.Count-1 do
  1776. begin
  1777. o:=TObject(Scope.Interfaces[i]);
  1778. if o is TPasProperty then
  1779. UseVariable(TPasProperty(o),rraRead,false)
  1780. else if o is TPasClassIntfMap then
  1781. begin
  1782. Map:=TPasClassIntfMap(o);
  1783. repeat
  1784. if Map.Intf<>nil then
  1785. UseClassOrRecType(TPasClassType(Map.Intf),paumElement);
  1786. if Map.Procs<>nil then
  1787. for j:=0 to Map.Procs.Count-1 do
  1788. UseProcedure(TPasProcedure(Map.Procs[j]));
  1789. Map:=Map.AncestorMap;
  1790. until Map=nil;
  1791. end
  1792. else
  1793. RaiseNotSupported(20180405190114,El,GetObjName(o));
  1794. end;
  1795. end;
  1796. var
  1797. i: Integer;
  1798. Member: TPasElement;
  1799. AllPublished, FirstTime, IsCOMInterfaceRoot: Boolean;
  1800. ProcScope: TPasProcedureScope;
  1801. ClassScope: TPasClassScope;
  1802. Ref: TResolvedReference;
  1803. j: Integer;
  1804. List, ProcList: TFPList;
  1805. o: TObject;
  1806. Map: TPasClassIntfMap;
  1807. ImplProc, IntfProc: TPasProcedure;
  1808. aClass: TPasClassType;
  1809. begin
  1810. FirstTime:=true;
  1811. case Mode of
  1812. paumAllExports: exit;
  1813. paumAllPasUsable:
  1814. begin
  1815. if MarkElementAsUsed(El) then
  1816. ElementVisited(El,Mode)
  1817. else
  1818. begin
  1819. if ElementVisited(El,Mode) then exit;
  1820. FirstTime:=false;
  1821. end;
  1822. end;
  1823. paumElement:
  1824. if not MarkElementAsUsed(El) then exit;
  1825. else
  1826. RaiseInconsistency(20170414152143,IntToStr(ord(Mode)));
  1827. end;
  1828. {$IFDEF VerbosePasAnalyzer}
  1829. writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime);
  1830. {$ENDIF}
  1831. aClass:=nil;
  1832. ClassScope:=nil;
  1833. IsCOMInterfaceRoot:=false;
  1834. if El is TPasClassType then
  1835. begin
  1836. aClass:=TPasClassType(El);
  1837. if aClass.IsForward then
  1838. begin
  1839. Ref:=aClass.CustomData as TResolvedReference;
  1840. UseClassOrRecType(Ref.Declaration as TPasClassType,Mode);
  1841. exit;
  1842. end;
  1843. ClassScope:=aClass.CustomData as TPasClassScope;
  1844. if ClassScope=nil then
  1845. exit; // ClassScope can be nil if msIgnoreInterfaces
  1846. if FirstTime then
  1847. begin
  1848. UseElType(El,ClassScope.DirectAncestor,paumElement);
  1849. UseElType(El,aClass.HelperForType,paumElement);
  1850. UseExpr(aClass.GUIDExpr);
  1851. // aClass.Interfaces: using a class does not use automatically the interfaces
  1852. if aClass.ObjKind=okInterface then
  1853. begin
  1854. UseDelegations;
  1855. if (aClass.InterfaceType=citCom) and (aClass.AncestorType=nil) then
  1856. IsCOMInterfaceRoot:=true;
  1857. end;
  1858. if (aClass.ObjKind=okClass) and (ScopeModule<>nil)
  1859. and (ClassScope.Interfaces<>nil) then
  1860. // when checking a single unit, mark all method+properties implementing the interfaces
  1861. MarkAllInterfaceImplementations(ClassScope);
  1862. end;
  1863. end
  1864. else if El is TPasRecordType then
  1865. begin
  1866. if (Mode<>paumAllPasUsable) and Resolver.IsTGUID(TPasRecordType(El)) then
  1867. for i:=0 to El.Members.Count-1 do
  1868. begin
  1869. Member:=TPasElement(El.Members[i]);
  1870. if Member is TPasVariable then
  1871. UseVariable(TPasVariable(Member),rraNone,true);
  1872. end;
  1873. end
  1874. else
  1875. RaiseNotSupported(20181229103139,El);
  1876. // members
  1877. AllPublished:=(Mode<>paumAllExports);
  1878. for i:=0 to El.Members.Count-1 do
  1879. begin
  1880. Member:=TPasElement(El.Members[i]);
  1881. if FirstTime and (Member is TPasProcedure) then
  1882. begin
  1883. ProcScope:=Member.CustomData as TPasProcedureScope;
  1884. if TPasProcedure(Member).IsOverride and (ProcScope.OverriddenProc<>nil) then
  1885. begin
  1886. // this is an override
  1887. AddOverride(ProcScope.OverriddenProc,Member);
  1888. if ScopeModule<>nil then
  1889. begin
  1890. // when analyzing a single module, all overrides are assumed to be called
  1891. UseProcedure(TPasProcedure(Member));
  1892. continue;
  1893. end;
  1894. end;
  1895. if IsCOMInterfaceRoot then
  1896. begin
  1897. case lowercase(Member.Name) of
  1898. 'queryinterface':
  1899. if (TPasProcedure(Member).ProcType.Args.Count=2) then
  1900. begin
  1901. UseProcedure(TPasProcedure(Member));
  1902. continue;
  1903. end;
  1904. '_addref':
  1905. if TPasProcedure(Member).ProcType.Args.Count=0 then
  1906. begin
  1907. UseProcedure(TPasProcedure(Member));
  1908. continue;
  1909. end;
  1910. '_release':
  1911. if TPasProcedure(Member).ProcType.Args.Count=0 then
  1912. begin
  1913. UseProcedure(TPasProcedure(Member));
  1914. continue;
  1915. end;
  1916. end;
  1917. //writeln('TPasAnalyzer.UseClassType ',El.FullName,' ',Mode,' ',Member.Name);
  1918. end;
  1919. end;
  1920. if AllPublished and (Member.Visibility=visPublished) then
  1921. begin
  1922. // include published
  1923. if not FirstTime then continue;
  1924. UseTypeInfo(Member);
  1925. end
  1926. else if Mode=paumElement then
  1927. continue
  1928. else if IsModuleInternal(Member) then
  1929. // private or strict private
  1930. continue
  1931. else if (Mode=paumAllPasUsable) and FirstTime
  1932. and ((Member.ClassType=TPasProperty) or (Member is TPasType)) then
  1933. begin
  1934. // non private property can be used by typeinfo by descendants in other units
  1935. UseTypeInfo(Member);
  1936. end
  1937. else
  1938. ; // else: class/record is in unit interface, mark all non private members
  1939. UseElement(Member,rraNone,true);
  1940. end;
  1941. if FirstTime and (ClassScope<>nil) then
  1942. begin
  1943. // method resolution
  1944. List:=ClassScope.Interfaces;
  1945. if List<>nil then
  1946. for i:=0 to List.Count-1 do
  1947. begin
  1948. o:=TObject(List[i]);
  1949. if o is TPasProperty then
  1950. begin
  1951. // interface delegation
  1952. // Note: This class is used. When the intftype is used, this delegation is used.
  1953. AddOverride(TPasType(aClass.Interfaces[i]),TPasProperty(o));
  1954. end
  1955. else if o is TPasClassIntfMap then
  1956. begin
  1957. Map:=TPasClassIntfMap(o);
  1958. while Map<>nil do
  1959. begin
  1960. ProcList:=Map.Procs;
  1961. if ProcList<>nil then
  1962. for j:=0 to ProcList.Count-1 do
  1963. begin
  1964. ImplProc:=TPasProcedure(ProcList[j]);
  1965. if ImplProc=nil then continue;
  1966. IntfProc:=TObject(Map.Intf.Members[j]) as TPasProcedure;
  1967. // This class is used. When the interface method is used, this method is used.
  1968. AddOverride(IntfProc,ImplProc);
  1969. end;
  1970. Map:=Map.AncestorMap;
  1971. end;
  1972. end
  1973. else
  1974. RaiseNotSupported(20180328224632,aClass,GetObjName(o));
  1975. end;
  1976. end;
  1977. end;
  1978. procedure TPasAnalyzer.UseVariable(El: TPasVariable;
  1979. Access: TResolvedRefAccess; UseFull: boolean);
  1980. var
  1981. Usage: TPAElement;
  1982. UseRead, UseWrite: boolean;
  1983. procedure UpdateVarAccess(IsRead, IsWrite: boolean);
  1984. begin
  1985. if IsRead then
  1986. case Usage.Access of
  1987. paiaNone: begin Usage.Access:=paiaRead; UseRead:=true; end;
  1988. paiaRead: ;
  1989. paiaWrite: begin Usage.Access:=paiaWriteRead; UseRead:=true; end;
  1990. paiaReadWrite: ;
  1991. paiaWriteRead: ;
  1992. else RaiseInconsistency(20170311182420,'');
  1993. end;
  1994. if IsWrite then
  1995. case Usage.Access of
  1996. paiaNone: begin Usage.Access:=paiaWrite; UseWrite:=true; end;
  1997. paiaRead: begin Usage.Access:=paiaReadWrite; UseWrite:=true; end;
  1998. paiaWrite: ;
  1999. paiaReadWrite: ;
  2000. paiaWriteRead: ;
  2001. else RaiseInconsistency(20170311182536,'');
  2002. end;
  2003. end;
  2004. var
  2005. Prop: TPasProperty;
  2006. i: Integer;
  2007. IsRead, IsWrite, CanRead, CanWrite: Boolean;
  2008. ClassEl: TPasClassType;
  2009. begin
  2010. if El=nil then exit;
  2011. {$IFDEF VerbosePasAnalyzer}
  2012. writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
  2013. {$ENDIF}
  2014. if El.ClassType=TPasProperty then
  2015. begin
  2016. Prop:=TPasProperty(El);
  2017. if Prop.Parent is TPasClassType then
  2018. begin
  2019. ClassEl:=TPasClassType(Prop.Parent);
  2020. if (ClassEl.ObjKind=okInterface) and IsTypeInfoUsed(ClassEl) then
  2021. begin
  2022. UseFull:=true;
  2023. UseTypeInfo(Prop);
  2024. end;
  2025. end;
  2026. end
  2027. else
  2028. Prop:=nil;
  2029. IsRead:=false;
  2030. IsWrite:=false;
  2031. if UseFull then
  2032. if (Prop<>nil) then
  2033. begin
  2034. CanRead:=Resolver.GetPasPropertyGetter(Prop)<>nil;
  2035. CanWrite:=Resolver.GetPasPropertySetter(Prop)<>nil;
  2036. if CanRead then
  2037. begin
  2038. if CanWrite then
  2039. Access:=rraReadAndAssign
  2040. else
  2041. Access:=rraRead;
  2042. end
  2043. else
  2044. if CanWrite then
  2045. Access:=rraAssign
  2046. else
  2047. Access:=rraNone;
  2048. end
  2049. else
  2050. Access:=rraRead;
  2051. case Access of
  2052. rraNone: ;
  2053. rraRead: IsRead:=true;
  2054. rraAssign: IsWrite:=true;
  2055. rraReadAndAssign,
  2056. rraVarParam,
  2057. rraOutParam: begin IsRead:=true; IsWrite:=true; end;
  2058. rraParamToUnknownProc: RaiseInconsistency(20170307153439,'');
  2059. else
  2060. RaiseInconsistency(20170308120949,'');
  2061. end;
  2062. UseRead:=false;
  2063. UseWrite:=false;
  2064. if MarkElementAsUsed(El) then
  2065. begin
  2066. // first access of this variable
  2067. Usage:=FindElement(El);
  2068. // first set flags
  2069. if El.Expr<>nil then
  2070. Usage.Access:=paiaWrite;
  2071. UpdateVarAccess(IsRead,IsWrite);
  2072. // then use recursively
  2073. UseElType(El,El.VarType,paumElement);
  2074. UseExpr(El.Expr);
  2075. UseExpr(El.LibraryName);
  2076. UseExpr(El.ExportName);
  2077. UseExpr(El.AbsoluteExpr);
  2078. if Prop<>nil then
  2079. begin
  2080. for i:=0 to Prop.Args.Count-1 do
  2081. UseElType(Prop,TPasArgument(Prop.Args[i]).ArgType,paumElement);
  2082. UseExpr(Prop.IndexExpr);
  2083. // ToDo: UseExpr(Prop.DispIDExpr);
  2084. // see UseTypeInfo: Prop.StoredAccessor, Prop.DefaultExpr
  2085. end;
  2086. end
  2087. else
  2088. begin
  2089. Usage:=FindElement(El);
  2090. if Usage=nil then
  2091. exit; // element outside of scope
  2092. // var is accessed another time
  2093. // first update flags
  2094. UpdateVarAccess(IsRead,IsWrite);
  2095. end;
  2096. // then use recursively
  2097. if Prop<>nil then
  2098. begin
  2099. {$IFDEF VerbosePasAnalyzer}
  2100. writeln('TPasAnalyzer.UseVariable Property=',Prop.FullName,
  2101. ' Ancestor=',GetElModName(Resolver.GetPasPropertyAncestor(Prop)),
  2102. ' UseRead=',UseRead,',Acc=',GetElModName(Resolver.GetPasPropertyGetter(Prop)),
  2103. ' UseWrite=',UseWrite,',Acc=',GetElModName(Resolver.GetPasPropertySetter(Prop)),
  2104. '');
  2105. {$ENDIF}
  2106. if UseRead then
  2107. UseElement(Resolver.GetPasPropertyGetter(Prop),rraRead,false);
  2108. if UseWrite then
  2109. UseElement(Resolver.GetPasPropertySetter(Prop),rraAssign,false);
  2110. end;
  2111. end;
  2112. procedure TPasAnalyzer.UseResourcestring(El: TPasResString);
  2113. begin
  2114. if not MarkElementAsUsed(El) then exit;
  2115. UseExpr(El.Expr);
  2116. end;
  2117. procedure TPasAnalyzer.UseArgument(El: TPasArgument; Access: TResolvedRefAccess
  2118. );
  2119. var
  2120. Usage: TPAElement;
  2121. IsRead, IsWrite: Boolean;
  2122. begin
  2123. IsRead:=false;
  2124. IsWrite:=false;
  2125. case Access of
  2126. rraNone: ;
  2127. rraRead: IsRead:=true;
  2128. rraAssign: IsWrite:=true;
  2129. rraReadAndAssign,
  2130. rraVarParam,
  2131. rraOutParam: begin IsRead:=true; IsWrite:=true; end;
  2132. rraParamToUnknownProc: RaiseInconsistency(20170308121031,'');
  2133. else
  2134. RaiseInconsistency(20170308121037,'');
  2135. end;
  2136. if MarkElementAsUsed(El) then
  2137. begin
  2138. // first time
  2139. Usage:=FindElement(El);
  2140. end
  2141. else
  2142. begin
  2143. // used again
  2144. Usage:=FindElement(El);
  2145. if Usage=nil then
  2146. RaiseNotSupported(20170308121928,El);
  2147. end;
  2148. UpdateAccess(IsWrite, IsRead, Usage);
  2149. end;
  2150. procedure TPasAnalyzer.UseResultElement(El: TPasResultElement;
  2151. Access: TResolvedRefAccess);
  2152. var
  2153. IsRead, IsWrite: Boolean;
  2154. Usage: TPAElement;
  2155. begin
  2156. IsRead:=false;
  2157. IsWrite:=false;
  2158. case Access of
  2159. rraNone: ;
  2160. rraRead: IsRead:=true;
  2161. rraAssign: IsWrite:=true;
  2162. rraReadAndAssign,
  2163. rraVarParam,
  2164. rraOutParam: begin IsRead:=true; IsWrite:=true; end;
  2165. rraParamToUnknownProc: RaiseInconsistency(20170308122319,'');
  2166. else
  2167. RaiseInconsistency(20170308122324,'');
  2168. end;
  2169. if MarkElementAsUsed(El) then
  2170. begin
  2171. // first time
  2172. Usage:=FindElement(El);
  2173. end
  2174. else
  2175. begin
  2176. // used again
  2177. Usage:=FindElement(El);
  2178. if Usage=nil then
  2179. RaiseNotSupported(20170308122333,El);
  2180. end;
  2181. UpdateAccess(IsWrite, IsRead, Usage);
  2182. end;
  2183. procedure TPasAnalyzer.EmitElementHints(El: TPasElement);
  2184. var
  2185. C: TClass;
  2186. begin
  2187. if El=nil then exit;
  2188. C:=El.ClassType;
  2189. if C.InheritsFrom(TPasVariable) then
  2190. EmitVariableHints(TPasVariable(El))
  2191. else if C.InheritsFrom(TPasType) then
  2192. EmitTypeHints(TPasType(El))
  2193. else if C.InheritsFrom(TPasProcedure) then
  2194. EmitProcedureHints(TPasProcedure(El))
  2195. else if C=TPasMethodResolution then
  2196. else
  2197. RaiseInconsistency(20170312093126,'');
  2198. end;
  2199. procedure TPasAnalyzer.EmitSectionHints(Section: TPasSection);
  2200. var
  2201. i: Integer;
  2202. UsedModule, aModule: TPasModule;
  2203. UsesClause: TPasUsesClause;
  2204. Use: TPasUsesUnit;
  2205. PosEl: TPasElement;
  2206. begin
  2207. {$IFDEF VerbosePasAnalyzer}
  2208. writeln('TPasAnalyzer.EmitSectionHints ',GetElModName(Section));
  2209. {$ENDIF}
  2210. // initialization, program or library sections
  2211. aModule:=Section.GetModule;
  2212. UsesClause:=Section.UsesClause;
  2213. for i:=0 to length(UsesClause)-1 do
  2214. begin
  2215. Use:=UsesClause[i];
  2216. if Use.Module is TPasModule then
  2217. begin
  2218. UsedModule:=TPasModule(Use.Module);
  2219. if CompareText(UsedModule.Name,'system')=0 then continue;
  2220. if not PAElementExists(UsedModule) then
  2221. begin
  2222. PosEl:=Use.Expr;
  2223. if PosEl=nil then PosEl:=Use;
  2224. EmitMessage(20170311191725,mtHint,nPAUnitNotUsed,sPAUnitNotUsed,
  2225. [UsedModule.Name,aModule.Name],PosEl);
  2226. end;
  2227. end;
  2228. end;
  2229. EmitDeclarationsHints(Section);
  2230. end;
  2231. procedure TPasAnalyzer.EmitDeclarationsHints(El: TPasDeclarations);
  2232. var
  2233. i: Integer;
  2234. Decl: TPasElement;
  2235. Usage: TPAElement;
  2236. begin
  2237. {$IFDEF VerbosePasAnalyzer}
  2238. writeln('TPasAnalyzer.EmitDeclarationsHints ',GetElModName(El));
  2239. {$ENDIF}
  2240. for i:=0 to El.Declarations.Count-1 do
  2241. begin
  2242. Decl:=TPasElement(El.Declarations[i]);
  2243. if Decl is TPasVariable then
  2244. EmitVariableHints(TPasVariable(Decl))
  2245. else if Decl is TPasType then
  2246. EmitTypeHints(TPasType(Decl))
  2247. else if Decl is TPasProcedure then
  2248. EmitProcedureHints(TPasProcedure(Decl))
  2249. else
  2250. begin
  2251. Usage:=FindElement(Decl);
  2252. if Usage=nil then
  2253. begin
  2254. // declaration was never used
  2255. EmitMessage(20170311231734,mtHint,nPALocalXYNotUsed,
  2256. sPALocalXYNotUsed,[Decl.ElementTypeName,Decl.Name],Decl);
  2257. end;
  2258. end;
  2259. end;
  2260. end;
  2261. procedure TPasAnalyzer.EmitTypeHints(El: TPasType);
  2262. var
  2263. C: TClass;
  2264. Usage: TPAElement;
  2265. i: Integer;
  2266. Member: TPasElement;
  2267. begin
  2268. {$IFDEF VerbosePasAnalyzer}
  2269. writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
  2270. {$ENDIF}
  2271. Usage:=FindElement(El);
  2272. if Usage=nil then
  2273. begin
  2274. // the whole type was never used
  2275. if (El.Visibility in [visPrivate,visStrictPrivate]) then
  2276. EmitMessage(20170312000020,mtHint,nPAPrivateTypeXNeverUsed,
  2277. sPAPrivateTypeXNeverUsed,[El.FullName],El)
  2278. else
  2279. begin
  2280. if (El is TPasClassType) and (TPasClassType(El).ObjKind=okInterface) then
  2281. exit;
  2282. EmitMessage(20170312000025,mtHint,nPALocalXYNotUsed,
  2283. sPALocalXYNotUsed,[El.ElementTypeName,El.Name],El);
  2284. end;
  2285. exit;
  2286. end;
  2287. // emit hints for sub elements
  2288. C:=El.ClassType;
  2289. if C=TPasRecordType then
  2290. begin
  2291. for i:=0 to TPasRecordType(El).Members.Count-1 do
  2292. EmitVariableHints(TObject(TPasRecordType(El).Members[i]) as TPasVariable);
  2293. end
  2294. else if C=TPasClassType then
  2295. begin
  2296. if TPasClassType(El).IsForward then exit;
  2297. for i:=0 to TPasClassType(El).Members.Count-1 do
  2298. begin
  2299. Member:=TPasElement(TPasClassType(El).Members[i]);
  2300. EmitElementHints(Member);
  2301. end;
  2302. end;
  2303. end;
  2304. procedure TPasAnalyzer.EmitVariableHints(El: TPasVariable);
  2305. var
  2306. Usage: TPAElement;
  2307. begin
  2308. {$IFDEF VerbosePasAnalyzer}
  2309. writeln('TPasAnalyzer.EmitVariableHints ',GetElModName(El));
  2310. {$ENDIF}
  2311. Usage:=FindElement(El);
  2312. if Usage=nil then
  2313. begin
  2314. // not used
  2315. if El.Visibility in [visPrivate,visStrictPrivate] then
  2316. begin
  2317. if El.ClassType=TPasConst then
  2318. EmitMessage(20170311234602,mtHint,nPAPrivateConstXNeverUsed,
  2319. sPAPrivateConstXNeverUsed,[El.FullName],El)
  2320. else if El.ClassType=TPasProperty then
  2321. EmitMessage(20170311234634,mtHint,nPAPrivatePropertyXNeverUsed,
  2322. sPAPrivatePropertyXNeverUsed,[El.FullName],El)
  2323. else
  2324. EmitMessage(20170311231412,mtHint,nPAPrivateFieldIsNeverUsed,
  2325. sPAPrivateFieldIsNeverUsed,[El.FullName],El);
  2326. end
  2327. else if El.ClassType=TPasVariable then
  2328. EmitMessage(20170311234201,mtHint,nPALocalVariableNotUsed,
  2329. sPALocalVariableNotUsed,[El.Name],El)
  2330. else
  2331. EmitMessage(20170314221334,mtHint,nPALocalXYNotUsed,
  2332. sPALocalXYNotUsed,[El.ElementTypeName,El.Name],El);
  2333. end
  2334. else if Usage.Access=paiaWrite then
  2335. begin
  2336. // write without read
  2337. if (vmExternal in El.VarModifiers)
  2338. or ((El.Parent is TPasClassType) and (TPasClassType(El.Parent).IsExternal)) then
  2339. exit;
  2340. if El.Visibility in [visPrivate,visStrictPrivate] then
  2341. EmitMessage(20170311234159,mtHint,nPAPrivateFieldIsAssignedButNeverUsed,
  2342. sPAPrivateFieldIsAssignedButNeverUsed,[El.FullName],El)
  2343. else
  2344. EmitMessage(20170311233825,mtHint,nPALocalVariableIsAssignedButNeverUsed,
  2345. sPALocalVariableIsAssignedButNeverUsed,[El.Name],El);
  2346. end;
  2347. end;
  2348. procedure TPasAnalyzer.EmitProcedureHints(El: TPasProcedure);
  2349. var
  2350. Args: TFPList;
  2351. i: Integer;
  2352. Arg: TPasArgument;
  2353. Usage: TPAElement;
  2354. ProcScope: TPasProcedureScope;
  2355. PosEl: TPasElement;
  2356. DeclProc, ImplProc: TPasProcedure;
  2357. FuncType: TPasFunctionType;
  2358. begin
  2359. {$IFDEF VerbosePasAnalyzer}
  2360. writeln('TPasAnalyzer.EmitProcedureHints ',GetElModName(El));
  2361. {$ENDIF}
  2362. ProcScope:=El.CustomData as TPasProcedureScope;
  2363. if ProcScope.DeclarationProc=nil then
  2364. DeclProc:=El
  2365. else
  2366. DeclProc:=ProcScope.DeclarationProc;
  2367. if ProcScope.ImplProc=nil then
  2368. ImplProc:=El
  2369. else
  2370. ImplProc:=ProcScope.ImplProc;
  2371. if not PAElementExists(DeclProc) then
  2372. begin
  2373. // procedure never used
  2374. if ProcScope.DeclarationProc=nil then
  2375. begin
  2376. if El.Visibility in [visPrivate,visStrictPrivate] then
  2377. EmitMessage(20170312093348,mtHint,nPAPrivateMethodIsNeverUsed,
  2378. sPAPrivateMethodIsNeverUsed,[El.FullName],El)
  2379. else
  2380. EmitMessage(20170312093418,mtHint,nPALocalXYNotUsed,
  2381. sPALocalXYNotUsed,[El.ElementTypeName,El.Name],El);
  2382. end;
  2383. exit;
  2384. end;
  2385. // procedure was used
  2386. if [pmAbstract,pmAssembler,pmExternal]*DeclProc.Modifiers<>[] then exit;
  2387. if [pmAssembler]*ImplProc.Modifiers<>[] then exit;
  2388. if El.Parent is TPasClassType then
  2389. begin
  2390. if TPasClassType(El.Parent).ObjKind=okInterface then exit;
  2391. end;
  2392. if ProcScope.DeclarationProc=nil then
  2393. begin
  2394. // check parameters
  2395. Args:=El.ProcType.Args;
  2396. for i:=0 to Args.Count-1 do
  2397. begin
  2398. Arg:=TPasArgument(Args[i]);
  2399. Usage:=FindElement(Arg);
  2400. if (Usage=nil) or (Usage.Access=paiaNone) then
  2401. begin
  2402. // parameter was never used
  2403. if (Arg.Parent is TPasProcedureType) and (Arg.Parent.Parent is TPasProcedure)
  2404. and ([pmVirtual,pmOverride]*TPasProcedure(Arg.Parent.Parent).Modifiers<>[]) then
  2405. EmitMessage(20180625153623,mtHint,nPAParameterInOverrideNotUsed,
  2406. sPAParameterInOverrideNotUsed,[Arg.Name],Arg)
  2407. else
  2408. EmitMessage(20170312094401,mtHint,nPAParameterNotUsed,
  2409. sPAParameterNotUsed,[Arg.Name],Arg);
  2410. end
  2411. else
  2412. begin
  2413. // parameter was used
  2414. if (Usage.Access=paiaWrite) and not (Arg.Access in [argOut,argVar]) then
  2415. EmitMessage(20170312095348,mtHint,nPAValueParameterIsAssignedButNeverUsed,
  2416. sPAValueParameterIsAssignedButNeverUsed,[Arg.Name],Arg);
  2417. end;
  2418. end;
  2419. // check result
  2420. if (El.ProcType is TPasFunctionType) then
  2421. begin
  2422. FuncType:=TPasFunctionType(TPasProcedure(El).ProcType);
  2423. PosEl:=FuncType.ResultEl;
  2424. if (ProcScope.ImplProc<>nil)
  2425. and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then
  2426. PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl;
  2427. Usage:=FindElement(FuncType.ResultEl);
  2428. if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then
  2429. // result was never used
  2430. EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet,
  2431. sPAFunctionResultDoesNotSeemToBeSet,[],PosEl)
  2432. else
  2433. begin
  2434. // result was used
  2435. end;
  2436. end;
  2437. end;
  2438. if El.Body<>nil then
  2439. begin
  2440. // check declarations
  2441. EmitDeclarationsHints(El.Body);
  2442. // ToDo: emit hints for statements
  2443. end;
  2444. end;
  2445. constructor TPasAnalyzer.Create;
  2446. var
  2447. m: TPAUseMode;
  2448. begin
  2449. CreateTree;
  2450. for m in TPAUseMode do
  2451. FChecked[m]:=TPasAnalyzerKeySet.Create(
  2452. {$ifdef pas2js}
  2453. @PasElementToHashName
  2454. {$else}
  2455. @ComparePointer
  2456. {$endif}
  2457. ,nil
  2458. );
  2459. FOverrideLists:=TPasAnalyzerKeySet.Create(
  2460. {$ifdef pas2js}
  2461. @PAOverrideList_ElToHashName,@PasElementToHashName
  2462. {$else}
  2463. @ComparePAOverrideLists,@CompareElementWithPAOverrideList
  2464. {$endif});
  2465. end;
  2466. destructor TPasAnalyzer.Destroy;
  2467. var
  2468. m: TPAUseMode;
  2469. begin
  2470. Clear;
  2471. FreeAndNil(FOverrideLists);
  2472. FreeAndNil(FUsedElements);
  2473. for m in TPAUseMode do
  2474. FreeAndNil(FChecked[m]);
  2475. inherited Destroy;
  2476. end;
  2477. procedure TPasAnalyzer.Clear;
  2478. var
  2479. m: TPAUseMode;
  2480. begin
  2481. FOverrideLists.FreeItems;
  2482. FUsedElements.FreeItems;
  2483. for m in TPAUseMode do
  2484. FChecked[m].Clear;
  2485. end;
  2486. procedure TPasAnalyzer.AnalyzeModule(aModule: TPasModule);
  2487. var
  2488. Mode: TPAUseMode;
  2489. begin
  2490. {$IFDEF VerbosePasAnalyzer}
  2491. writeln('TPasAnalyzer.AnalyzeModule START ',GetElModName(aModule));
  2492. {$ENDIF}
  2493. if Resolver=nil then
  2494. RaiseInconsistency(20170314223032,'TPasAnalyzer.AnalyzeModule missing Resolver');
  2495. if FUsedElements.Count>0 then
  2496. RaiseInconsistency(20170315153243,'');
  2497. ScopeModule:=aModule;
  2498. if (aModule is TPasProgram) or (aModule is TPasLibrary) then
  2499. Mode:=paumAllExports
  2500. else
  2501. Mode:=paumAllPasUsable;
  2502. UseModule(aModule,Mode);
  2503. {$IFDEF VerbosePasAnalyzer}
  2504. writeln('TPasAnalyzer.AnalyzeModule END ',GetElModName(aModule));
  2505. {$ENDIF}
  2506. end;
  2507. procedure TPasAnalyzer.AnalyzeWholeProgram(aStartModule: TPasProgram);
  2508. begin
  2509. {$IFDEF VerbosePasAnalyzer}
  2510. writeln('TPasAnalyzer.AnalyzeWholeProgram START ',GetElModName(aStartModule));
  2511. {$ENDIF}
  2512. if Resolver=nil then
  2513. RaiseInconsistency(20170315153201,'TPasAnalyzer.AnalyzeWholeProgram missing Resolver');
  2514. if FUsedElements.Count>0 then
  2515. RaiseInconsistency(20170315153252,'');
  2516. ScopeModule:=nil;
  2517. UseModule(aStartModule,paumAllExports);
  2518. MarkElementAsUsed(aStartModule); // always mark the start
  2519. {$IFDEF VerbosePasAnalyzer}
  2520. writeln('TPasAnalyzer.AnalyzeWholeProgram END ',GetElModName(aStartModule));
  2521. {$ENDIF}
  2522. end;
  2523. procedure TPasAnalyzer.EmitModuleHints(aModule: TPasModule);
  2524. begin
  2525. {$IFDEF VerbosePasAnalyzer}
  2526. writeln('TPasAnalyzer.EmitModuleHints ',GetElModName(aModule));
  2527. {$ENDIF}
  2528. if aModule.ClassType=TPasProgram then
  2529. EmitSectionHints(TPasProgram(aModule).ProgramSection)
  2530. else if aModule.ClassType=TPasLibrary then
  2531. EmitSectionHints(TPasLibrary(aModule).LibrarySection)
  2532. else
  2533. begin
  2534. // unit
  2535. EmitSectionHints(aModule.InterfaceSection);
  2536. EmitSectionHints(aModule.ImplementationSection);
  2537. end;
  2538. //EmitBlockHints(aModule.InitializationSection);
  2539. //EmitBlockHints(aModule.FinalizationSection);
  2540. end;
  2541. function TPasAnalyzer.FindUsedElement(El: TPasElement): TPAElement;
  2542. var
  2543. ProcScope: TPasProcedureScope;
  2544. begin
  2545. if not IsIdentifier(El) then exit(nil);
  2546. if El is TPasProcedure then
  2547. begin
  2548. ProcScope:=El.CustomData as TPasProcedureScope;
  2549. if (ProcScope<>nil) and (ProcScope.DeclarationProc<>nil) then
  2550. El:=ProcScope.DeclarationProc;
  2551. end;
  2552. Result:=FindElement(El);
  2553. end;
  2554. function TPasAnalyzer.IsUsed(El: TPasElement): boolean;
  2555. begin
  2556. Result:=FindUsedElement(El)<>nil;
  2557. end;
  2558. function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean;
  2559. begin
  2560. Result:=FChecked[paumTypeInfo].ContainsItem(El);
  2561. end;
  2562. function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean;
  2563. begin
  2564. if El=nil then
  2565. exit(true);
  2566. if El.ClassType=TInterfaceSection then
  2567. exit(false);
  2568. if IsExport(El) then exit(false);
  2569. case El.Visibility of
  2570. visPrivate,visStrictPrivate: exit(true);
  2571. visPublished: exit(false);
  2572. end;
  2573. Result:=IsModuleInternal(El.Parent);
  2574. end;
  2575. function TPasAnalyzer.IsExport(El: TPasElement): boolean;
  2576. begin
  2577. if El is TPasVariable then
  2578. Result:=[vmExport,vmPublic]*TPasVariable(El).VarModifiers<>[]
  2579. else if El is TPasProcedure then
  2580. Result:=[pmExport,pmPublic]*TPasProcedure(El).Modifiers<>[]
  2581. else
  2582. Result:=false;
  2583. end;
  2584. function TPasAnalyzer.IsIdentifier(El: TPasElement): boolean;
  2585. var
  2586. C: TClass;
  2587. begin
  2588. C:=El.ClassType;
  2589. Result:=C.InheritsFrom(TPasType)
  2590. or C.InheritsFrom(TPasVariable)
  2591. or C.InheritsFrom(TPasProcedure)
  2592. or C.InheritsFrom(TPasModule)
  2593. or (C=TPasArgument)
  2594. or (C=TPasResString);
  2595. end;
  2596. function TPasAnalyzer.IsImplBlockEmpty(El: TPasImplBlock): boolean;
  2597. begin
  2598. Result:=true;
  2599. if (El=nil) or (El.Elements.Count=0) then exit;
  2600. Result:=false;
  2601. end;
  2602. procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
  2603. MsgNumber: integer; Fmt: String;
  2604. const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
  2605. PosEl: TPasElement);
  2606. var
  2607. Msg: TPAMessage;
  2608. El: TPasElement;
  2609. ProcScope: TPasProcedureScope;
  2610. ModScope: TPasModuleScope;
  2611. Scanner: TPascalScanner;
  2612. State: TWarnMsgState;
  2613. begin
  2614. {$IFDEF VerbosePasAnalyzer}
  2615. //writeln('TPasAnalyzer.EmitMessage [',Id,'] ',MsgType,': (',MsgNumber,') Fmt={',Fmt,'} PosEl='+GetElModName(PosEl));
  2616. {$ENDIF}
  2617. if MsgType>=mtWarning then
  2618. begin
  2619. El:=PosEl;
  2620. while El<>nil do
  2621. begin
  2622. if El is TPasProcedure then
  2623. begin
  2624. ProcScope:=El.CustomData as TPasProcedureScope;
  2625. if ProcScope.ImplProc<>nil then
  2626. ProcScope:=ProcScope.ImplProc.CustomData as TPasProcedureScope;
  2627. case MsgType of
  2628. mtHint: if not (bsHints in ProcScope.BoolSwitches) then exit;
  2629. mtNote: if not (bsNotes in ProcScope.BoolSwitches) then exit;
  2630. mtWarning: if not (bsWarnings in ProcScope.BoolSwitches) then exit;
  2631. end;
  2632. break;
  2633. end
  2634. else if El is TPasModule then
  2635. begin
  2636. ModScope:=TPasModule(El).CustomData as TPasModuleScope;
  2637. case MsgType of
  2638. mtHint: if not (bsHints in ModScope.BoolSwitches) then exit;
  2639. mtNote: if not (bsNotes in ModScope.BoolSwitches) then exit;
  2640. mtWarning: if not (bsWarnings in ModScope.BoolSwitches) then exit;
  2641. end;
  2642. break;
  2643. end;
  2644. El:=El.Parent;
  2645. end;
  2646. if (Resolver<>nil) and (Resolver.CurrentParser<>nil) then
  2647. begin
  2648. Scanner:=Resolver.CurrentParser.Scanner;
  2649. if Scanner<>nil then
  2650. begin
  2651. State:=Scanner.WarnMsgState[MsgNumber];
  2652. case State of
  2653. wmsOff:
  2654. begin
  2655. {$IFDEF VerbosePasAnalyzer}
  2656. writeln('TPasAnalyzer.EmitMessage ignoring [',Id,'] ',MsgType,': (',MsgNumber,') Fmt={',Fmt,'} PosEl='+GetElModName(PosEl));
  2657. {$ENDIF}
  2658. exit;
  2659. end;
  2660. wmsError:
  2661. MsgType:=mtError;
  2662. end;
  2663. end;
  2664. end;
  2665. end;
  2666. Msg:=TPAMessage.Create;
  2667. Msg.Id:=Id;
  2668. Msg.MsgType:=MsgType;
  2669. Msg.MsgNumber:=MsgNumber;
  2670. Msg.MsgPattern:=Fmt;
  2671. Msg.MsgText:=SafeFormat(Fmt,Args);
  2672. CreateMsgArgs(Msg.Args,Args);
  2673. Msg.PosEl:=PosEl;
  2674. Msg.Filename:=PosEl.SourceFilename;
  2675. Resolver.UnmangleSourceLineNumber(PosEl.SourceLinenumber,Msg.Row,Msg.Col);
  2676. EmitMessage(Msg);
  2677. end;
  2678. procedure TPasAnalyzer.EmitMessage(Msg: TPAMessage);
  2679. begin
  2680. if not Assigned(OnMessage) then
  2681. begin
  2682. Msg.Release;
  2683. exit;
  2684. end;
  2685. {$IFDEF VerbosePasAnalyzer}
  2686. writeln('TPasAnalyzer.EmitMessage [',Msg.Id,'] ',Msg.MsgType,': (',Msg.MsgNumber,') "',Msg.MsgText,'" at ',Resolver.GetElementSourcePosStr(Msg.PosEl),' ScopeModule=',GetObjName(ScopeModule));
  2687. {$ENDIF}
  2688. try
  2689. OnMessage(Self,Msg);
  2690. finally
  2691. Msg.Release;
  2692. end;
  2693. end;
  2694. class function TPasAnalyzer.GetWarnIdentifierNumbers(Identifier: string; out
  2695. MsgNumbers: TIntegerDynArray): boolean;
  2696. procedure SetNumber(Number: integer);
  2697. begin
  2698. {$IF FPC_FULLVERSION>=30101}
  2699. MsgNumbers:=[Number];
  2700. {$ELSE}
  2701. Setlength(MsgNumbers,1);
  2702. MsgNumbers[0]:=Number;
  2703. {$ENDIF}
  2704. end;
  2705. begin
  2706. if Identifier='' then exit(false);
  2707. if Identifier[1] in ['0'..'9'] then exit(false);
  2708. Result:=true;
  2709. case UpperCase(Identifier) of
  2710. // Delphi+FPC
  2711. 'NO_RETVAL': SetNumber(nPAFunctionResultDoesNotSeemToBeSet); // Function result is not set.
  2712. else
  2713. Result:=false;
  2714. end;
  2715. end;
  2716. function TPasAnalyzer.GetUsedElements: TFPList;
  2717. begin
  2718. Result:=FUsedElements.GetList;
  2719. end;
  2720. end.