1 { 2 *************************************************************************** 3 * * 4 * This source is free software; you can redistribute it and/or modify * 5 * it under the terms of the GNU General Public License as published by * 6 * the Free Software Foundation; either version 2 of the License, or * 7 * (at your option) any later version. * 8 * * 9 * This code is distributed in the hope that it will be useful, but * 10 * WITHOUT ANY WARRANTY; without even the implied warranty of * 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 12 * General Public License for more details. * 13 * * 14 * A copy of the GNU General Public License is available on the World * 15 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also * 16 * obtain it by writing to the Free Software Foundation, * 17 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * 18 * * 19 *************************************************************************** 20 21 Author: Mattias Gaertner 22 23 Abstract: 24 An IDE dialog to show various internals about a TCodeTreeNode at cursor. 25 } 26 unit CodyNodeInfoDlg; 27 28 {$mode objfpc}{$H+} 29 30 interface 31 32 uses 33 Classes, SysUtils, Laz_AVL_Tree, 34 // LCL 35 Forms, Controls, Graphics, Dialogs, ButtonPanel, ComCtrls, StdCtrls, 36 // IDEIntf 37 SrcEditorIntf, 38 // CodeTools 39 CodeToolManager, CodeTree, FindDeclarationCache, PascalParserTool, 40 LinkScanner, CodeCache, BasicCodeTools, FindDeclarationTool, SourceLog, 41 CodyStrConsts, FileProcs, LazFileUtils; 42 43 type 44 45 { TCodyNodeInfoDialog } 46 47 TCodyNodeInfoDialog = class(TForm) 48 ButtonPanel1: TButtonPanel; 49 CodeBufferMemo: TMemo; 50 CodeBuffersComboBox: TComboBox; 51 LinksMemo: TMemo; 52 PageControl1: TPageControl; 53 ReportMemo: TMemo; 54 ReportTabSheet: TTabSheet; 55 CodeBuffersTabSheet: TTabSheet; 56 LinksTabSheet: TTabSheet; 57 procedure CodeBuffersComboBoxSelect(Sender: TObject); 58 procedure FormCreate(Sender: TObject); 59 private 60 procedure ReportBaseTypeCache(Report: TStringList; 61 Tool: TFindDeclarationTool; Node: TCodeTreeNode); 62 procedure ReportAllNodes(Report: TStringList; 63 Tool: TFindDeclarationTool); 64 procedure ShowCodeBuffer(Filename: string); 65 public 66 procedure UpdateReport; 67 end; 68 69 procedure ShowCodeNodeInfoDialog(Sender: TObject); 70 71 implementation 72 73 procedure ShowCodeNodeInfoDialog(Sender: TObject); 74 var 75 CodyNodeInfoDialog: TCodyNodeInfoDialog; 76 begin 77 CodyNodeInfoDialog:=TCodyNodeInfoDialog.Create(nil); 78 try 79 CodyNodeInfoDialog.ShowModal; 80 finally 81 CodyNodeInfoDialog.Free; 82 end; 83 end; 84 85 { TCodyNodeInfoDialog } 86 87 procedure TCodyNodeInfoDialog.FormCreate(Sender: TObject); 88 begin 89 Caption:=crsCodeNodeInformation; 90 ReportTabSheet.Caption:=crsReport; 91 CodeBuffersTabSheet.Caption:=crsCodeBuffers; 92 LinksTabSheet.Caption:=crsLinks; 93 ButtonPanel1.CloseButton.Caption:=crsClose; 94 PageControl1.PageIndex:=0; 95 UpdateReport; 96 end; 97 98 procedure TCodyNodeInfoDialog.CodeBuffersComboBoxSelect(Sender: TObject); 99 begin 100 ShowCodeBuffer(CodeBuffersComboBox.Text); 101 end; 102 103 procedure TCodyNodeInfoDialog.ReportBaseTypeCache(Report: TStringList; 104 Tool: TFindDeclarationTool; Node: TCodeTreeNode); 105 106 procedure ReportNode(Prefix: string; ATool: TFindDeclarationTool; 107 ANode: TCodeTreeNode); 108 var 109 s: String; 110 begin 111 if (ATool=nil) or (ANode=nil) then begin 112 Report.Add(Prefix+'Tool='+DbgSName(ATool)+' Node='+DbgSName(ANode)); 113 exit; 114 end; 115 Report.Add(Prefix+'Node.Desc='+ANode.DescAsString+' Start='+ATool.CleanPosToStr(ANode.StartPos,true)); 116 s:=dbgstr(ATool.Src,ANode.StartPos,ANode.EndPos-ANode.StartPos); 117 if length(s)>100 then 118 s:=copy(s,1,48)+'...'+copy(s,length(s)-47,48); 119 Report.Add(GetIndentStr(length(Prefix)+2)+'Src="'+s+'"'); 120 end; 121 122 var 123 Cache: TBaseTypeCache; 124 BaseContext: TFindContext; 125 LastBaseContext: TFindContext; 126 i: Integer; 127 Visited: TFPList; 128 NextTool: TFindDeclarationTool; 129 NextNode: TCodeTreeNode; 130 begin 131 LastBaseContext:=CleanFindContext; 132 i:=0; 133 Visited:=TFPList.Create; 134 try 135 while Node<>nil do begin 136 inc(i); 137 ReportNode(dbgs(i)+': ',Tool,Node); 138 if not (Node.Cache is TBaseTypeCache) then begin 139 Report.Add('Node.Cache='+DbgSName(Node.Cache)); 140 exit; 141 end; 142 if Visited.IndexOf(Node)>=0 then begin 143 Report.Add('ERROR: CIRCLE'); 144 exit; 145 end; 146 Visited.Add(Node); 147 Cache:=TBaseTypeCache(Node.Cache); 148 BaseContext:=CreateFindContext(TFindDeclarationTool(Cache.BaseTool),Cache.BaseNode); 149 if CompareFindContexts(@LastBaseContext,@BaseContext)<>0 then begin 150 ReportNode(' Base: ',BaseContext.Tool,BaseContext.Node); 151 LastBaseContext:=BaseContext; 152 end; 153 154 NextTool:=TFindDeclarationTool(Cache.NextTool); 155 NextNode:=Cache.NextNode; 156 if (NextNode<>nil) and (NextTool=nil) then begin 157 Report.Add('Error: node without tool: Cache.NextTool=nil, Cache.NextNode='+NextNode.DescAsString); 158 exit; 159 end; 160 if NextNode=Node then begin 161 // base node reached 162 exit; 163 end; 164 Node:=NextNode; 165 Tool:=NextTool; 166 end; 167 finally 168 Visited.Free; 169 end; 170 end; 171 172 procedure TCodyNodeInfoDialog.ReportAllNodes(Report: TStringList; 173 Tool: TFindDeclarationTool); 174 var 175 Node: TCodeTreeNode; 176 s: String; 177 begin 178 Report.Add(''); 179 Report.Add('Nodes:'); 180 if Tool=nil then exit; 181 if Tool.Tree=nil then exit; 182 Node:=Tool.Tree.Root; 183 while Node<>nil do begin 184 s:=GetIndentStr(Node.GetLevel*2); 185 s:=s+Node.DescAsString; 186 s:=s+',Start='+IntToStr(Node.StartPos)+'='+Tool.CleanPosToStr(Node.StartPos); 187 s:=s+',End='+IntToStr(Node.EndPos)+'='+Tool.CleanPosToStr(Node.EndPos); 188 Report.Add(s); 189 Node:=Node.Next; 190 end; 191 end; 192 193 procedure TCodyNodeInfoDialog.ShowCodeBuffer(Filename: string); 194 var 195 Code: TCodeBuffer; 196 i: Integer; 197 sl: TStringList; 198 begin 199 Code:=CodeToolBoss.LoadFile(Filename,false,false); 200 sl:=TStringList.Create; 201 if Code<>nil then begin 202 for i:=0 to Code.LineCount-1 do begin 203 sl.Add('Line='+dbgs(i+1)+' Start='+dbgs(Code.GetLineStart(i))+' ="'+dbgstr(Code.GetLine(i,true))+'"'); 204 end; 205 end; 206 CodeBufferMemo.Lines.Assign(sl); 207 sl.Free; 208 end; 209 210 procedure TCodyNodeInfoDialog.UpdateReport; 211 var 212 SrcEdit: TSourceEditorInterface; 213 CursorPos: TCodeXYPosition; 214 sl: TStringList; 215 Tool: TCodeTool; 216 CleanPos: integer; 217 Node: TCodeTreeNode; 218 SrcCode: TSourceLog; 219 i: Integer; 220 UsedCodeBuffers: TAVLTree; 221 AVLNode: TAVLTreeNode; 222 Filenames: TStringList; 223 CodeBuf: TCodeBuffer; 224 Scanner: TLinkScanner; 225 Link: TSourceLink; 226 LinkSize: Integer; 227 s: String; 228 begin 229 Tool:=nil; 230 sl:=TStringList.Create; 231 try 232 SrcEdit:=SourceEditorManagerIntf.ActiveEditor; 233 if SrcEdit=nil then begin 234 sl.Add('no source editor'); 235 exit; 236 end; 237 sl.Add('File='+SrcEdit.FileName); 238 CursorPos.X:=SrcEdit.CursorTextXY.X; 239 CursorPos.Y:=SrcEdit.CursorTextXY.Y; 240 sl.Add('Line='+dbgs(CursorPos.Y)); 241 sl.Add('Column='+dbgs(CursorPos.X)); 242 CursorPos.Code:=SrcEdit.CodeToolsBuffer as TCodeBuffer; 243 if not CodeToolBoss.InitCurCodeTool(CursorPos.Code) then begin 244 sl.Add('CodeToolBoss.InitCurCodeTool failed. Maybe unit of include file not found.'); 245 exit; 246 end; 247 try 248 Tool:=CodeToolBoss.CurCodeTool; 249 if CompareFilenames(Tool.MainFilename,SrcEdit.FileName)<>0 then 250 sl.Add('Unit='+Tool.MainFilename); 251 Tool.BuildTreeAndGetCleanPos(trTillCursor,lsrEnd,CursorPos,CleanPos, 252 [btSetIgnoreErrorPos]); 253 254 // nodes 255 sl.Add('Scanner.ScannedRange='+dbgs(Tool.Scanner.ScannedRange)); 256 sl.Add('Tool.ScannedRange='+dbgs(Tool.ScannedRange)); 257 Node:=Tool.FindDeepestNodeAtPos(CleanPos,false); 258 if Node=nil then begin 259 try 260 Tool.RaiseCursorOutsideCode(CursorPos); 261 except 262 on E: Exception do begin 263 sl.Add('Error: '+E.Message); 264 end; 265 end; 266 end else begin 267 sl.Add('Node.Desc='+Node.DescAsString); 268 sl.Add('Node.SubDesc=%'+binStr(Node.SubDesc,16)); 269 sl.Add('Node.StartPos='+dbgs(Node.StartPos)+'='+Tool.CleanPosToStr(Node.StartPos)); 270 sl.Add('Node.EndPos='+dbgs(Node.EndPos)+'='+Tool.CleanPosToStr(Node.EndPos)); 271 sl.Add('Node Src>>>>>>>>>>>>>>>>>>'); 272 SrcCode:=TSourceLog.Create(copy(Tool.Src,Node.StartPos,Node.EndPos-Node.StartPos)); 273 for i:=0 to SrcCode.LineCount-1 do begin 274 sl.Add('Line='+dbgs(i)+',CleanPos='+dbgs(Node.StartPos+SrcCode.GetLineStart(i)-1)+'="'+dbgstr(SrcCode.GetLine(i,true))+'"'); 275 end; 276 SrcCode.Free; 277 sl.Add('Node Src<<<<<<<<<<<<<<<<<<'); 278 279 ReportBaseTypeCache(sl,Tool,Node); 280 ReportAllNodes(sl,Tool); 281 end; 282 283 // codebuffers 284 Filenames:=TStringList.Create; 285 if Tool.Scanner<>nil then begin 286 UsedCodeBuffers:=Tool.Scanner.CreateTreeOfSourceCodes; 287 AVLNode:=UsedCodeBuffers.FindLowest; 288 while AVLNode<>nil do begin 289 CodeBuf:=TCodeBuffer(AVLNode.Data); 290 Filenames.Add(CodeBuf.Filename); 291 AVLNode:=UsedCodeBuffers.FindSuccessor(AVLNode); 292 end; 293 UsedCodeBuffers.Free; 294 end; 295 CodeBuffersComboBox.Items.Assign(Filenames); 296 Filenames.Free; 297 if CodeBuffersComboBox.Items.Count>0 then begin 298 CodeBuffersComboBox.Text:=CodeBuffersComboBox.Items[0]; 299 ShowCodeBuffer(CodeBuffersComboBox.Text); 300 end else begin 301 CodeBuffersComboBox.Text:=''; 302 end; 303 304 except 305 on e: Exception do CodeToolBoss.HandleException(e); 306 end; 307 finally 308 if CodeToolBoss.ErrorMessage<>'' then begin 309 sl.Add('Error: '+CodeToolBoss.ErrorMessage); 310 if CodeToolBoss.ErrorCode<>nil then begin 311 sl.Add('Error: '+CodeToolBoss.ErrorCode.Filename); 312 if CodeToolBoss.ErrorLine>0 then 313 sl.Add('Error line='+dbgs(CodeToolBoss.ErrorLine)+' column='+dbgs(CodeToolBoss.ErrorColumn)); 314 end; 315 end; 316 ReportMemo.Lines.Assign(sl); 317 sl.Free; 318 end; 319 // links 320 sl:=TStringList.Create; 321 try 322 sl.Clear; 323 if Tool.Scanner<>nil then begin 324 Scanner:=Tool.Scanner; 325 sl.Add('MainFilename:'+Scanner.MainFilename); 326 sl.Add('ScannedRange='+dbgs(Scanner.ScannedRange)); 327 sl.Add('==================================='); 328 sl.Add('InitialValues:'); 329 sl.Add(Scanner.InitialValues.AsString); 330 sl.Add('==================================='); 331 sl.Add('Values:'); 332 sl.Add(Scanner.Values.AsString); 333 sl.Add('==================================='); 334 sl.Add('IsUnit='+dbgs(Scanner.IsUnit)); 335 sl.Add('SourceName='+Scanner.SourceName); 336 sl.Add('==================================='); 337 sl.Add('Links:'); 338 for i:=0 to Scanner.LinkCount-1 do begin 339 Link:=Scanner.Links[i]; 340 s:=dbgs(i)+'/'+dbgs(Scanner.LinkCount)+': Kind='+dbgs(Link.Kind); 341 if Link.Code<>nil then 342 s+=',File='+ExtractFileName(TCodeBuffer(Link.Code).Filename); 343 s+=',CleanedPos='+dbgs(Link.CleanedPos)+',SrcPos='+dbgs(Link.SrcPos); 344 LinkSize:=Scanner.LinkSize(i); 345 s+=',Size='+dbgs(LinkSize); 346 if LinkSize>60 then 347 s+=',Code="'+dbgstr(Scanner.CleanedSrc,Link.CleanedPos,30)+'...'+dbgstr(Scanner.CleanedSrc,Link.CleanedPos+LinkSize-30,30)+'"' 348 else 349 s+=',Code="'+dbgstr(Scanner.CleanedSrc,Link.CleanedPos,LinkSize)+'"'; 350 sl.Add(s); 351 end; 352 sl.Add('==================================='); 353 end; 354 LinksMemo.Lines.Assign(sl); 355 finally 356 sl.Free; 357 end; 358 end; 359 360 {$R *.lfm} 361 362 end. 363 364