diff --git a/components/codetools/basiccodetools.pas b/components/codetools/basiccodetools.pas index 25e35e97b5..c5864b6053 100644 --- a/components/codetools/basiccodetools.pas +++ b/components/codetools/basiccodetools.pas @@ -30,7 +30,6 @@ unit BasicCodeTools; {$ifdef FPC} {$mode objfpc} {$else} - // delphi? if so then Windows is not defined but instead MSWindows is defined => define Windows in this case {$ifdef MSWindows} {$define Windows} {$endif} diff --git a/components/codetools/finddeclarationtool.pas b/components/codetools/finddeclarationtool.pas index 0264e6973b..f193daade0 100644 --- a/components/codetools/finddeclarationtool.pas +++ b/components/codetools/finddeclarationtool.pas @@ -79,7 +79,7 @@ uses Classes, SysUtils, CodeToolsStrConsts, CodeTree, CodeAtom, CustomCodeTool, SourceLog, KeywordFuncLists, BasicCodeTools, LinkScanner, CodeCache, DirectoryCacher, AVL_Tree, PascalParserTool, - PascalReaderTool, FileProcs, LazFileUtils, LazUtilities, + PascalReaderTool, FileProcs, LazFileUtils, LazUtilities, LazUTF8, DefineTemplates, FindDeclarationCache; type @@ -3561,10 +3561,11 @@ var end; var - CommentStart, CommentEnd: integer; + CommentStart, CommentEnd, Col, StartCol: integer; Node: TCodeTreeNode; - aUnitName, UnitInFilename, Line: string; + aUnitName, UnitInFilename, Line, Literal: string; NewCode: TCodeBuffer; + p, StartP: PChar; begin Result:=false; Found:=ffatNone; @@ -3654,10 +3655,47 @@ begin // fallback: ignore parsed code and read the line at cursor directly if (CursorPos.Y<1) or (CursorPos.Y>CursorPos.Code.LineCount) then exit; - Line:=CursorPos.Code.GetLine(CursorPos.Y,false); + Line:=CursorPos.Code.GetLine(CursorPos.Y-1,false); + {$IFDEF VerboseFindFileAtCursor} + debugln(['TFindDeclarationTool.FindFileAtCursor Line="',copy(Line,1,CursorPos.X-1),'|',copy(Line,CursorPos.X,200),'"']); + {$ENDIF} if CursorPos.X>length(Line) then exit; if ffatLiteral in SearchFor then begin - // ToDo: check literal + // check literal + p:=PChar(Line); + Col:=1; + repeat + if p^=#0 then begin + break; + end else if p^='''' then begin + StartCol:=Col; + inc(Col); + inc(p); + StartP:=p; + repeat + case p^ of + #0: break; + '''': break; + #9: Col:=(Col+8) and not 7; + else inc(p,UTF8CharacterLength(p)); + end; + until false; + if (CursorPos.X>=StartCol) and (CursorPos.X<=Col) then begin + Literal:=copy(Line,Col,p-StartP); + if not FilenameIsAbsolute(Literal) then + Literal:=TrimFilename(ExtractFilePath(Scanner.MainFilename)+Literal); + if FilenameIsAbsolute(Literal) + and DirectoryCache.Pool.FileExists(Literal) then begin + Found:=ffatLiteral; + FoundFilename:=Literal; + exit(true); + end; + end; + if p^=#0 then break; + end; + inc(p); + inc(Col); + until false; end; if ffatComment in SearchFor then begin // ToDo: check simple diff --git a/components/codetools/tests/testfinddeclaration.pas b/components/codetools/tests/testfinddeclaration.pas index a3221f8485..3091143bad 100644 --- a/components/codetools/tests/testfinddeclaration.pas +++ b/components/codetools/tests/testfinddeclaration.pas @@ -327,17 +327,17 @@ begin // --- used unit --- // test cursor on 'unit2' if not CodeToolBoss.FindFileAtCursor(Code,6,1,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at uses unit2 failed'); + Fail('CodeToolBoss.FindFileAtCursor at uses unit2'); AssertEquals('FindFileAtCursor at uses unit2 Found',ord(ffatUsedUnit),ord(Found)); AssertEquals('FindFileAtCursor at uses unit2 FoundFilename','unit2.pas',FoundFilename); // test cursor on 'in' if not CodeToolBoss.FindFileAtCursor(Code,12,1,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at uses unit2-in failed'); + Fail('CodeToolBoss.FindFileAtCursor at uses unit2-in'); AssertEquals('FindFileAtCursor at uses unit2-in Found',ord(ffatUsedUnit),ord(Found)); AssertEquals('FindFileAtCursor at uses unit2-in FoundFilename','unit2.pas',FoundFilename); // test cursor on in-file literal if not CodeToolBoss.FindFileAtCursor(Code,16,1,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at uses unit2-in-literal failed'); + Fail('CodeToolBoss.FindFileAtCursor at uses unit2-in-literal'); AssertEquals('FindFileAtCursor at uses unit2-in-lit Found',ord(ffatUsedUnit),ord(Found)); AssertEquals('FindFileAtCursor at uses unit2-in-lit FoundFilename','unit2.pas',FoundFilename); @@ -347,13 +347,13 @@ begin +'{$i unit2.pas}'+LineEnding; SubUnit2Code.Source:=''; if not CodeToolBoss.FindFileAtCursor(Code,1,2,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at enabled include directive of empty inc failed'); + Fail('CodeToolBoss.FindFileAtCursor at enabled include directive of empty inc'); AssertEquals('FindFileAtCursor at enabled include directive of empty Found',ord(ffatIncludeFile),ord(Found)); AssertEquals('FindFileAtCursor at enabled include directive of empty FoundFilename','unit2.pas',FoundFilename); SubUnit2Code.Source:='{$define a}'; if not CodeToolBoss.FindFileAtCursor(Code,1,2,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at enabled include directive of non-empty inc failed'); + Fail('CodeToolBoss.FindFileAtCursor at enabled include directive of non-empty inc'); AssertEquals('FindFileAtCursor at enabled include directive of non-empty Found',ord(ffatIncludeFile),ord(Found)); AssertEquals('FindFileAtCursor at enabled include directive of non-empty FoundFilename','unit2.pas',FoundFilename); @@ -365,7 +365,7 @@ begin +'{$endif}'+LineEnding; SubUnit2Code.Source:=''; if not CodeToolBoss.FindFileAtCursor(Code,1,3,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at disabled include directive failed'); + Fail('CodeToolBoss.FindFileAtCursor at disabled include directive'); AssertEquals('FindFileAtCursor at disabled include directive Found',ord(ffatDisabledIncludeFile),ord(Found)); AssertEquals('FindFileAtCursor at disabled include directive FoundFilename','unit2.pas',FoundFilename); @@ -373,17 +373,36 @@ begin Code.Source:='program test1;'+LineEnding +'{$R test1.lfm}'+LineEnding; if not CodeToolBoss.FindFileAtCursor(Code,1,2,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at enabled resource directive failed'); + Fail('CodeToolBoss.FindFileAtCursor at enabled resource directive'); AssertEquals('FindFileAtCursor at enabled resource directive Found',ord(ffatResource),ord(Found)); AssertEquals('FindFileAtCursor at enabled resource directive FoundFilename','test1.lfm',FoundFilename); Code.Source:='program test1;'+LineEnding +'{$R *.lfm}'+LineEnding; if not CodeToolBoss.FindFileAtCursor(Code,1,2,Found,FoundFilename) then - Fail('CodeToolBoss.FindFileAtCursor at enabled resource directive failed'); + Fail('CodeToolBoss.FindFileAtCursor at enabled resource directive'); AssertEquals('FindFileAtCursor at enabled resource directive Found',ord(ffatResource),ord(Found)); AssertEquals('FindFileAtCursor at enabled resource directive FoundFilename','test1.lfm',FoundFilename); + // --- disabled resource directive --- + Code.Source:='program test1;'+LineEnding + +'{$ifdef disabled}'+LineEnding + +'{$R test1.lfm}'+LineEnding + +'{$endif}'+LineEnding; + if not CodeToolBoss.FindFileAtCursor(Code,1,3,Found,FoundFilename) then + Fail('CodeToolBoss.FindFileAtCursor at disabled resource directive'); + AssertEquals('FindFileAtCursor at disabled resource directive Found',ord(ffatDisabledResource),ord(Found)); + AssertEquals('FindFileAtCursor at disabled resource directive FoundFilename','test1.lfm',FoundFilename); + + // --- literal --- + Code.Source:='program test1;'+LineEnding + +'const Cfg=''unit2.pas'';'+LineEnding; + if not CodeToolBoss.FindFileAtCursor(Code,11,2,Found,FoundFilename) then + Fail('CodeToolBoss.FindFileAtCursor in literal'); + AssertEquals('FindFileAtCursor in literal Found',ord(ffatLiteral),ord(Found)); + AssertEquals('FindFileAtCursor in literal FoundFilename','unit2.pas',FoundFilename); + + finally Code.IsDeleted:=true; SubUnit2Code.IsDeleted:=true;