From b0b5163778eb153c002c97ecc87925c439d55375 Mon Sep 17 00:00:00 2001 From: mattias Date: Sat, 7 Jun 2014 19:37:21 +0000 Subject: [PATCH] IDE: fpc msg parser: darwin linker reference error git-svn-id: trunk@45383 - --- components/codetools/codetoolmanager.pas | 19 ++-- components/leakview/leakinfo.pas | 57 +--------- ide/etfpcmsgparser.pas | 131 ++++++++++++++++++----- ide/main.pp | 57 +++++++++- 4 files changed, 175 insertions(+), 89 deletions(-) diff --git a/components/codetools/codetoolmanager.pas b/components/codetools/codetoolmanager.pas index 3418268f4a..a75ada4a13 100644 --- a/components/codetools/codetoolmanager.pas +++ b/components/codetools/codetoolmanager.pas @@ -68,7 +68,7 @@ type TOnFindDefineProperty = procedure(Sender: TObject; const PersistentClassName, AncestorClassName, Identifier: string; var IsDefined: boolean) of object; - TOnFindGDBSource = procedure(Sender: TObject; SrcType: TCodeTreeNodeDesc; + TOnFindFPCMangledSource = procedure(Sender: TObject; SrcType: TCodeTreeNodeDesc; const SrcName: string; out SrcFilename: string) of object; ECodeToolManagerError = class(Exception); @@ -109,6 +109,7 @@ type FOnAfterApplyChanges: TOnAfterApplyCTChanges; FOnBeforeApplyChanges: TOnBeforeApplyCTChanges; FOnCheckAbort: TOnCodeToolCheckAbort; + FOnFindFPCMangledSource: TOnFindFPCMangledSource; FOnGatherExternalChanges: TOnGatherExternalChanges; FOnFindDefinePropertyForContext: TOnFindDefinePropertyForContext; FOnFindDefineProperty: TOnFindDefineProperty; @@ -832,10 +833,12 @@ type out NewX, NewY, NewTopLine: integer): boolean; // gdb stacktraces - function FindGBDIdentifier(GDBIdentifier: string; out aComplete: boolean; - out aMessage: string; const OnFindSource: TOnFindGDBSource; + function FindFPCMangledIdentifier(GDBIdentifier: string; out aComplete: boolean; + out aMessage: string; const OnFindSource: TOnFindFPCMangledSource; out NewCode: TCodeBuffer; out NewX, NewY, NewTopLine: integer): boolean; + property OnFindFPCMangledSource: TOnFindFPCMangledSource + read FOnFindFPCMangledSource write FOnFindFPCMangledSource; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3830,9 +3833,9 @@ begin end; end; -function TCodeToolManager.FindGBDIdentifier(GDBIdentifier: string; out +function TCodeToolManager.FindFPCMangledIdentifier(GDBIdentifier: string; out aComplete: boolean; out aMessage: string; - const OnFindSource: TOnFindGDBSource; out NewCode: TCodeBuffer; out NewX, + const OnFindSource: TOnFindFPCMangledSource; out NewCode: TCodeBuffer; out NewX, NewY, NewTopLine: integer): boolean; { Examples: compiler built-in @@ -3904,6 +3907,9 @@ var if Assigned(OnFindSource) then begin OnFindSource(Self,ctnUnit,TheUnitName,aFilename); Result:=aFilename<>''; + end else if Assigned(OnFindFPCMangledSource) then begin + OnFindFPCMangledSource(Self,ctnUnit,TheUnitName,aFilename); + Result:=aFilename<>''; end; end; @@ -4066,12 +4072,13 @@ begin end; // unknown operator => use only SrcFilename //debugln(['TCodeToolManager.FindGBDIdentifier operator not yet supported: ',dbgstr(p^)]); + aMessage:='operator not supported: '+dbgstr(p^); exit; end else begin // example: ?? end; - aMessage:='unkown identifier "'+GDBIdentifier+'"'; + aMessage:='unknown identifier "'+GDBIdentifier+'"'; end; function TCodeToolManager.CompleteCode(Code: TCodeBuffer; X,Y,TopLine: integer; diff --git a/components/leakview/leakinfo.pas b/components/leakview/leakinfo.pas index 0d5db606fe..16ab323de5 100644 --- a/components/leakview/leakinfo.pas +++ b/components/leakview/leakinfo.pas @@ -112,8 +112,6 @@ type function TrcNumberAfter(var Num: Int64; const AfterSub: string): Boolean; function TrcNumberAfter(var Num: Integer; const AfterSub: string): Boolean; function TrcNumFirstAndAfter(var FirstNum, AfterNum: Int64; const AfterSub: string): Boolean; - procedure OnFindCTSource(Sender: TObject; SrcType: TCodeTreeNodeDesc; - const SrcName: string; out SrcFilename: string); procedure ParseTraceLine(s: string; var line: TStackLine); procedure ParseStackTrace(trace: TStackTrace); @@ -268,57 +266,6 @@ end; { THeapTrcInfo } -procedure THeapTrcInfo.OnFindCTSource(Sender: TObject; - SrcType: TCodeTreeNodeDesc; const SrcName: string; out SrcFilename: string); -var - aProject: TLazProject; - i: Integer; - SrcEdit: TSourceEditorInterface; - Code: TCodeBuffer; - Tool: TCodeTool; -begin - case SrcType of - ctnProgram: - begin - // check active project - aProject:=LazarusIDE.ActiveProject; - if (aProject<>nil) and (aProject.MainFile<>nil) then begin - SrcFilename:=aProject.MainFile.Filename; - if FilenameIsAbsolute(SrcFilename) - and ((SrcName='') - or (SysUtils.CompareText(ExtractFileNameOnly(SrcFilename),SrcName)=0)) - then - exit; // found - end; - end; - end; - // search in source editor - for i:=0 to SourceEditorManagerIntf.SourceEditorCount-1 do begin - SrcEdit:=SourceEditorManagerIntf.SourceEditors[i]; - SrcFilename:=SrcEdit.FileName; - if CompareText(ExtractFileNameOnly(SrcFileName),SrcName)<>0 then - continue; - case SrcType of - ctnUnit: - if not FilenameIsPascalUnit(SrcFileName) then - continue; - else - // a pascal program can have any file name - // but we don't want to open program.res or program.txt - // => check if source is Pascal - // => load source and check if codetools can parse at least one node - Code:=CodeToolBoss.LoadFile(SrcFilename,true,false); - if Code=nil then continue; - CodeToolBoss.Explore(Code,Tool,false,true); - if (Tool=nil) or (Tool.Tree.Root=nil) then - continue; - end; - exit; // found - end; - // not found - SrcFilename:=''; -end; - function THeapTrcInfo.PosInTrc(const SubStr: string; CaseSensetive: Boolean): Boolean; begin Result := TrcIndexnil then begin line.FileName:=SrcCode.Filename; @@ -635,7 +582,7 @@ begin while (i<=length(s)) and (s[i] in ['a'..'z','A'..'Z','0'..'9','_','$','?']) do inc(i); GDBIdentifier:=copy(s,1,i-1); - CodeToolBoss.FindGBDIdentifier(GDBIdentifier,Complete,TheErrorMsg,@OnFindCTSource, + CodeToolBoss.FindFPCMangledIdentifier(GDBIdentifier,Complete,TheErrorMsg,@OnFindCTSource, SrcCode,SrcX,SrcY,SrcTopLine); if SrcCode<>nil then begin line.FileName:=SrcCode.Filename; diff --git a/ide/etfpcmsgparser.pas b/ide/etfpcmsgparser.pas index 344a7d0b2d..05d0d5b8af 100644 --- a/ide/etfpcmsgparser.pas +++ b/ide/etfpcmsgparser.pas @@ -147,6 +147,8 @@ type fFileExists: TFilenameToPointerTree; fIncludePath: string; // only valid if fIncludePathValidForWorkerDir=Tool.WorkerDirectory fIncludePathValidForWorkerDir: string; + fUnitPath: string; // only valid if fUnitPathValidForWorkerDir=Tool.WorkerDirectory + fUnitPathValidForWorkerDir: string; fLastWorkerImprovedMessage: array[TExtToolParserSyncPhase] of integer; fLineToMsgID: TPatternToMsgIDs; fMissingFPCMsgItem: TFPCMsgItem; @@ -160,6 +162,8 @@ type fMsgItemThereWereErrorsCompiling: TFPCMsgItem; fMsgItemUnitNotUsed: TFPCMsgItem; fOutputIndex: integer; // current OutputIndex given by ReadLine + procedure FetchIncludePath(aPhase: TExtToolParserSyncPhase; MsgWorkerDir: String); + procedure FetchUnitPath(aPhase: TExtToolParserSyncPhase; MsgWorkerDir: String); function FileExists(const Filename: string; aSynchronized: boolean): boolean; function CheckForMsgId(p: PChar): boolean; // (MsgId) message function CheckForFileLineColMessage(p: PChar): boolean; // the normal messages: filename(y,x): Hint: .. @@ -465,15 +469,21 @@ function GetFPCMsgValue1(const Src, Pattern: string; out Value1: string } var p: SizeInt; + l: SizeInt; begin + Value1:=''; + Result:=false; + if length(Src)1) and (not CompareMem(Pointer(Src),Pointer(Pattern),p-1)) then exit; + // check end pattern + l:=length(Pattern)-p-2; + if (l>0) + and (not CompareMem(Pointer(Src)+length(Src)-l,Pointer(Pattern)+p+2,l)) then exit; + Value1:=copy(Src,p,length(Src)-length(Pattern)+2); + Result:=true; end; function GetFPCMsgValues(Src, Pattern: string; out Value1, Value2: string @@ -1083,6 +1093,10 @@ begin fIncludePathValidForWorkerDir:=Tool.WorkerDirectory; fIncludePath:=CodeToolBoss.GetIncludePathForDirectory( ChompPathDelim(fIncludePathValidForWorkerDir)); + // get include search path + fUnitPathValidForWorkerDir:=Tool.WorkerDirectory; + fUnitPath:=CodeToolBoss.GetUnitPathForDirectory( + ChompPathDelim(fUnitPathValidForWorkerDir)); end; procedure TIDEFPCParser.InitReading; @@ -1883,7 +1897,7 @@ procedure TIDEFPCParser.ImproveMsgLinkerUndefinedReference( /path//blaunit.pas:45: undefined reference to `BLAUNIT_BLABLA' } - function CheckForLDFileAndLineNumber: boolean; + function CheckForLinuxLDFileAndLineNumber: boolean; var p: PChar; Msg: String; @@ -1925,16 +1939,52 @@ procedure TIDEFPCParser.ImproveMsgLinkerUndefinedReference( Result:=true; MsgLine.Msg:=copy(Msg,p-PChar(Msg)+1,length(Msg)); - MsgLine.Filename:=aFilename; - MsgLine.Line:=LineNumber; - MsgLine.Column:=1; + MsgLine.SetSourcePosition(aFilename,LineNumber,1); + MsgLine.Urgency:=mluError; + end; + + function CheckForDarwinLDReferencedFrom: boolean; + { For example: + "_UNIT1_GIBTESNICHT", referenced from: + } + var + MangledName: string; + aComplete: boolean; + aErrorMsg: string; + NewCode: TCodeBuffer; + NewX: integer; + NewY: integer; + NewTopLine: integer; + begin + Result:=false; + if MsgLine.HasSourcePosition then exit; + // check for ' "_FPC-Mangled-Identifier", referenced from: + if not etFPCMsgParser.GetFPCMsgValue1(MsgLine.Msg,' "_$1", referenced from:', + MangledName) + then exit; + Result:=true; + case aPhase of + etpspAfterReadLine: + begin + NeedSynchronize:=true; + exit; + end; + etpspAfterSync: exit; + end; + // in main threads + CodeToolBoss.FindFPCMangledIdentifier(MangledName,aComplete,aErrorMsg, + nil,NewCode,NewX,NewY,NewTopLine); + if NewCode=nil then exit; + Result:=true; + MsgLine.SetSourcePosition(NewCode.Filename,NewY,NewX); MsgLine.Urgency:=mluError; end; begin if MsgLine.SubTool<>SubToolFPCLinker then exit; - if CheckForLDFileAndLineNumber then exit; + if CheckForLinuxLDFileAndLineNumber then exit; + if CheckForDarwinLDReferencedFrom then exit; end; procedure TIDEFPCParser.ImproveMsgIdentifierPosition( @@ -2077,6 +2127,48 @@ begin end; end; +procedure TIDEFPCParser.FetchIncludePath(aPhase: TExtToolParserSyncPhase; + MsgWorkerDir: String); +begin + if MsgWorkerDir='' then + MsgWorkerDir:=Tool.WorkerDirectory; + if fIncludePathValidForWorkerDir<>MsgWorkerDir then begin + // fetch include path from IDE + case aPhase of + etpspAfterReadLine: + NeedSynchronize:=true; + etpspSynchronized: + begin + fIncludePathValidForWorkerDir:=MsgWorkerDir; + fIncludePath:=CodeToolBoss.GetIncludePathForDirectory( + ChompPathDelim(MsgWorkerDir)); + NeedAfterSync:=true; + end; + end; + end; +end; + +procedure TIDEFPCParser.FetchUnitPath(aPhase: TExtToolParserSyncPhase; + MsgWorkerDir: String); +begin + if MsgWorkerDir='' then + MsgWorkerDir:=Tool.WorkerDirectory; + if fUnitPathValidForWorkerDir<>MsgWorkerDir then begin + // fetch unit path from IDE + case aPhase of + etpspAfterReadLine: + NeedSynchronize:=true; + etpspSynchronized: + begin + fUnitPathValidForWorkerDir:=MsgWorkerDir; + fUnitPath:=CodeToolBoss.GetUnitPathForDirectory( + ChompPathDelim(MsgWorkerDir)); + NeedAfterSync:=true; + end; + end; + end; +end; + function TIDEFPCParser.CheckForMsgId(p: PChar): boolean; var MsgItem: TFPCMsgItem; @@ -2426,20 +2518,7 @@ begin if (not FilenameIsAbsolute(aFilename)) then begin // short file name => 2. try include path MsgWorkerDir:=MsgLine.Attribute[FPCMsgAttrWorkerDirectory]; - if fIncludePathValidForWorkerDir<>MsgWorkerDir then begin - // fetch include path from IDE - case aPhase of - etpspAfterReadLine: - NeedSynchronize:=true; - etpspSynchronized: - begin - fIncludePathValidForWorkerDir:=MsgWorkerDir; - fIncludePath:=CodeToolBoss.GetIncludePathForDirectory( - ChompPathDelim(MsgWorkerDir)); - NeedAfterSync:=true; - end; - end; - end; + FetchIncludePath(aPhase,MsgWorkerDir); if (aPhase in [etpspAfterReadLine,etpspAfterSync]) and (fIncludePathValidForWorkerDir=MsgWorkerDir) then begin // include path is valid and in worker thread diff --git a/ide/main.pp b/ide/main.pp index 17754fa53a..3c0cea6622 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -71,8 +71,8 @@ uses HelpIntfs, Graphics, ExtCtrls, Dialogs, InterfaceBase, UTF8Process, LazLogger, lazutf8classes, LazFileCache, // codetools - FileProcs, FindDeclarationTool, LinkScanner, BasicCodeTools, - CodeToolsStructs, CodeToolManager, CodeCache, DefineTemplates, KeywordFuncLists, + FileProcs, FindDeclarationTool, LinkScanner, BasicCodeTools, CodeToolsStructs, + CodeToolManager, CodeCache, DefineTemplates, KeywordFuncLists, CodeTree, // synedit AllSynEdit, SynEditKeyCmds, SynBeautifier, SynEditMarks, // IDE interface @@ -621,6 +621,9 @@ type var CodeBuffers: TFPList; // stopping when CodeBuffers=nil var ExpandedFilenames: TStrings ); + procedure CodeToolBossFindFPCMangledSource(Sender: TObject; + SrcType: TCodeTreeNodeDesc; const SrcName: string; out SrcFilename: string); + function CTMacroFunctionProject(Data: Pointer): boolean; procedure OnCompilerParseStampIncreased; procedure CodeToolBossScannerInit(Self: TCodeToolManager; @@ -1991,6 +1994,55 @@ begin end; end; +procedure TMainIDE.CodeToolBossFindFPCMangledSource(Sender: TObject; + SrcType: TCodeTreeNodeDesc; const SrcName: string; out SrcFilename: string); +var + i: Integer; + SrcEdit: TSourceEditorInterface; + Code: TCodeBuffer; + Tool: TCodeTool; +begin + case SrcType of + ctnProgram: + begin + // check active project + if (Project1<>nil) and (Project1.MainFile<>nil) then begin + SrcFilename:=Project1.MainFile.Filename; + if FilenameIsAbsolute(SrcFilename) + and ((SrcName='') + or (SysUtils.CompareText(ExtractFileNameOnly(SrcFilename),SrcName)=0)) + then + exit; // found + end; + end; + end; + // search in source editor + for i:=0 to SourceEditorManagerIntf.SourceEditorCount-1 do begin + SrcEdit:=SourceEditorManagerIntf.SourceEditors[i]; + SrcFilename:=SrcEdit.FileName; + if CompareText(ExtractFileNameOnly(SrcFileName),SrcName)<>0 then + continue; + case SrcType of + ctnUnit: + if not FilenameIsPascalUnit(SrcFileName) then + continue; + else + // a pascal program can have any file name + // but we don't want to open program.res or program.txt + // => check if source is Pascal + // => load source and check if codetools can parse at least one node + Code:=CodeToolBoss.LoadFile(SrcFilename,true,false); + if Code=nil then continue; + CodeToolBoss.Explore(Code,Tool,false,true); + if (Tool=nil) or (Tool.Tree.Root=nil) then + continue; + end; + exit; // found + end; + // not found + SrcFilename:=''; +end; + {------------------------------------------------------------------------------} procedure TMainIDE.MainIDEFormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -9310,6 +9362,7 @@ begin OnGetMethodName:=@OnCodeToolBossGetMethodName; OnGetIndenterExamples:=@OnCodeToolBossGetIndenterExamples; OnScannerInit:=@CodeToolBossScannerInit; + OnFindFPCMangledSource:=@CodeToolBossFindFPCMangledSource; end; CodeToolsOpts.AssignGlobalDefineTemplatesToTree(CodeToolBoss.DefineTree);