mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-22 07:59:47 +02:00
IDE: added quickfix for note local variable not used, remove
git-svn-id: trunk@25498 -
This commit is contained in:
parent
5cc2b11ac5
commit
eaa1ff2fba
@ -66,8 +66,6 @@ function ExtractCommentContent(const ASource: string; CommentStart: integer;
|
||||
function FindMainUnitHint(const ASource: string; out Filename: string): boolean;
|
||||
|
||||
// indent
|
||||
procedure GetLineStartEndAtPosition(const Source:string; Position:integer;
|
||||
var LineStart,LineEnd:integer);
|
||||
function GetLineIndent(const Source: string; Position: integer): integer;
|
||||
function GetLineIndentWithTabs(const Source: string; Position: integer;
|
||||
TabWidth: integer): integer;
|
||||
@ -93,6 +91,9 @@ function IsValidIdentPair(const NamePair: string;
|
||||
out First, Second: string): boolean;
|
||||
|
||||
// line/code ends
|
||||
procedure GetLineStartEndAtPosition(const Source:string; Position:integer;
|
||||
var LineStart,LineEnd:integer);
|
||||
function GetLineStartPosition(const Source:string; Position:integer): integer;
|
||||
function LineEndCount(const Txt: string): integer; inline;
|
||||
function LineEndCount(const Txt: string; out LengthOfLastLine:integer): integer; inline;
|
||||
function LineEndCount(const Txt: string; StartPos, EndPos: integer;
|
||||
@ -108,7 +109,8 @@ function FindLineEndOrCodeInFrontOfPosition(const Source: string;
|
||||
StopAtDirectives: boolean = true; SkipSemicolonComma: boolean = true): integer;
|
||||
function FindLineEndOrCodeAfterPosition(const Source: string;
|
||||
Position, MaxPosition: integer; NestedComments: boolean;
|
||||
StopAtDirectives: boolean = true; SkipEmptyLines: boolean = false): integer;
|
||||
StopAtDirectives: boolean = true; SkipEmptyLines: boolean = false;
|
||||
IncludeLineEnd: boolean = false): integer;
|
||||
function FindFirstLineEndInFrontOfInCode(const Source: string;
|
||||
Position, MinPosition: integer; NestedComments: boolean): integer;
|
||||
function FindFirstLineEndAfterInCode(const Source: string;
|
||||
@ -1332,9 +1334,8 @@ procedure GetLineStartEndAtPosition(const Source:string; Position:integer;
|
||||
var LineStart,LineEnd:integer);
|
||||
begin
|
||||
LineStart:=Position;
|
||||
while (LineStart>0) and (not (Source[LineStart] in [#10,#13])) do
|
||||
while (LineStart>1) and (not (Source[LineStart-1] in [#10,#13])) do
|
||||
dec(LineStart);
|
||||
inc(LineStart);
|
||||
LineEnd:=Position;
|
||||
while (LineEnd<=length(Source)) and (not (Source[LineEnd] in [#10,#13])) do
|
||||
inc(LineEnd);
|
||||
@ -2248,10 +2249,10 @@ begin
|
||||
if (Result>length(Source)) then Result:=length(Source);
|
||||
if Result=0 then exit;
|
||||
// search beginning of line
|
||||
while (Result>1) and (not (Source[Result] in [#10,#13])) do
|
||||
while (Result>1) and (not (Source[Result-1] in [#10,#13])) do
|
||||
dec(Result);
|
||||
// search
|
||||
while (Result<length(Source)) and (Source[Result]<' ') do inc(Result);
|
||||
while (Result<=length(Source)) and (Source[Result] in [' ',#9]) do inc(Result);
|
||||
end;
|
||||
|
||||
function GetLineIndent(const Source: string; Position: integer): integer;
|
||||
@ -2273,7 +2274,8 @@ end;
|
||||
|
||||
function FindLineEndOrCodeAfterPosition(const Source: string;
|
||||
Position, MaxPosition: integer; NestedComments: boolean;
|
||||
StopAtDirectives: boolean; SkipEmptyLines: boolean): integer;
|
||||
StopAtDirectives: boolean; SkipEmptyLines: boolean;
|
||||
IncludeLineEnd: boolean): integer;
|
||||
{ search forward for a line end or code
|
||||
ignore line ends in comments
|
||||
Result is Position of Start of Line End
|
||||
@ -2284,6 +2286,10 @@ function FindLineEndOrCodeAfterPosition(const Source: string;
|
||||
|
||||
1. var i: integer;|#
|
||||
var j: integer;
|
||||
|
||||
If IncludeLineEnd then
|
||||
var i: integer;|
|
||||
# var j: integer;
|
||||
|
||||
2. var i: integer;| (*
|
||||
*) #var j: integer;
|
||||
@ -2293,6 +2299,8 @@ function FindLineEndOrCodeAfterPosition(const Source: string;
|
||||
#
|
||||
// comment
|
||||
var j: integer;
|
||||
|
||||
if IncludeLineEnd then the # will be one line below
|
||||
|
||||
4. SkipEmptyLines=true
|
||||
var i: integer;|
|
||||
@ -2386,6 +2394,13 @@ begin
|
||||
#10,#13:
|
||||
begin
|
||||
if SkipEmptyLines then DoSkipEmptyLines(Result);
|
||||
if IncludeLineEnd and (Result<=SrcLen) and (Source[Result] in [#10,#13])
|
||||
then begin
|
||||
inc(Result);
|
||||
if (Result<=SrcLen) and (Source[Result] in [#10,#13])
|
||||
and (Source[Result-1]<>Source[Result]) then
|
||||
inc(Result);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
#9,' ',';':
|
||||
@ -3955,6 +3970,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetLineStartPosition(const Source: string; Position: integer): integer;
|
||||
begin
|
||||
Result:=Position;
|
||||
while (Result>1) and (not (Source[Result-1] in [#10,#13])) do
|
||||
dec(Result);
|
||||
end;
|
||||
|
||||
function LineEndCount(const Txt: string): integer;
|
||||
var
|
||||
LengthOfLastLine: integer;
|
||||
|
@ -419,7 +419,7 @@ type
|
||||
function GatherOverloads(Code: TCodeBuffer; X,Y: integer;
|
||||
out Graph: TDeclarationOverloadsGraph): boolean;
|
||||
|
||||
// rename identifier
|
||||
// rename, remove identifier
|
||||
function FindReferences(IdentifierCode: TCodeBuffer;
|
||||
X, Y: integer; TargetCode: TCodeBuffer; SkipComments: boolean;
|
||||
var ListOfPCodeXYPosition: TFPList): boolean;
|
||||
@ -429,6 +429,8 @@ type
|
||||
const OldIdentifier, NewIdentifier: string): boolean;
|
||||
function ReplaceWord(Code: TCodeBuffer; const OldWord, NewWord: string;
|
||||
ChangeStrings: boolean): boolean;
|
||||
function RemoveIdentifierDefinition(Code: TCodeBuffer; X, Y: integer
|
||||
): boolean; // e.g. remove the variable definition at X,Y
|
||||
|
||||
// resourcestring sections
|
||||
function GatherResourceStringSections(
|
||||
@ -2323,6 +2325,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCodeToolManager.RemoveIdentifierDefinition(Code: TCodeBuffer; X,
|
||||
Y: integer): boolean;
|
||||
var
|
||||
CursorPos: TCodeXYPosition;
|
||||
begin
|
||||
Result:=false;
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TCodeToolManager.RemoveIdentifierDefinition A ',Code.Filename,' X=',X,' Y=',Y);
|
||||
{$ENDIF}
|
||||
if not InitCurCodeTool(Code) then exit;
|
||||
CursorPos.X:=X;
|
||||
CursorPos.Y:=Y;
|
||||
CursorPos.Code:=Code;
|
||||
try
|
||||
Result:=FCurCodeTool.RemoveIdentifierDefinition(CursorPos,SourceChangeCache);
|
||||
except
|
||||
on e: Exception do HandleException(e);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCodeToolManager.GatherResourceStringSections(Code: TCodeBuffer;
|
||||
X, Y: integer; CodePositions: TCodeXYPositions): boolean;
|
||||
var
|
||||
|
@ -211,7 +211,7 @@ type
|
||||
procedure GetLineInfo(ACleanPos: integer;
|
||||
out ALineStart, ALineEnd, AFirstAtomStart, ALastAtomEnd: integer);
|
||||
function FindLineEndOrCodeAfterPosition(StartPos: integer;
|
||||
SkipEmptyLines: boolean = false): integer;
|
||||
SkipEmptyLines: boolean = false; IncludeLineEnd: boolean = false): integer;
|
||||
function FindLineEndOrCodeInFrontOfPosition(StartPos: integer): integer;
|
||||
function FindLineEndOrCodeInFrontOfPosition(StartPos: integer;
|
||||
StopAtDirectives: boolean): integer;
|
||||
@ -2431,7 +2431,7 @@ begin
|
||||
end;
|
||||
|
||||
function TCustomCodeTool.FindLineEndOrCodeAfterPosition(StartPos: integer;
|
||||
SkipEmptyLines: boolean): integer;
|
||||
SkipEmptyLines: boolean; IncludeLineEnd: boolean): integer;
|
||||
{ Searches a nice position in the cleaned source after StartPos.
|
||||
It will skip any space or comments (not directives) till next
|
||||
line end or compiler directive or code or include file end.
|
||||
@ -2443,7 +2443,8 @@ begin
|
||||
LinkEnd:=Scanner.LinkCleanedEndPos(LinkIndex);
|
||||
if LinkEnd>StartPos then
|
||||
Result:=BasicCodeTools.FindLineEndOrCodeAfterPosition(Src,
|
||||
StartPos,LinkEnd-1,Scanner.NestedComments,true,SkipEmptyLines)
|
||||
StartPos,LinkEnd-1,Scanner.NestedComments,true,SkipEmptyLines,
|
||||
IncludeLineEnd)
|
||||
else
|
||||
Result:=StartPos;
|
||||
end;
|
||||
|
@ -195,6 +195,10 @@ type
|
||||
SearchInAncestors: boolean;
|
||||
out ListOfPInstancePropInfo: TFPList): boolean;
|
||||
|
||||
// variables, constants, types
|
||||
function RemoveIdentifierDefinition(const CursorPos: TCodeXYPosition;
|
||||
SourceChangeCache: TSourceChangeCache): boolean;
|
||||
|
||||
// blocks (e.g. begin..end)
|
||||
function FindBlockCounterPart(const CursorPos: TCodeXYPosition;
|
||||
out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
|
||||
@ -5075,6 +5079,109 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TStandardCodeTool.RemoveIdentifierDefinition(
|
||||
const CursorPos: TCodeXYPosition; SourceChangeCache: TSourceChangeCache
|
||||
): boolean;
|
||||
var
|
||||
CleanCursorPos: integer;
|
||||
Node: TCodeTreeNode;
|
||||
PrevSibling: TCodeTreeNode;
|
||||
NextSibling: TCodeTreeNode;
|
||||
DeleteStartPos: LongInt;
|
||||
DeleteEndPos: LongInt;
|
||||
DeleteFirstTokenOfLine: Boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
BuildTreeAndGetCleanPos(trAll,CursorPos,CleanCursorPos,[]);
|
||||
Node:=BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos,true);
|
||||
if Node.Desc in AllIdentifierDefinitions then begin
|
||||
// Examples:
|
||||
// var i, X: integer; -> var i[, X]: integer;
|
||||
// var i, X, j: integer; -> var i, [X, ]j: integer;
|
||||
// var X, i: integer; -> var [X, ]i: integer;
|
||||
// type X = integer;
|
||||
// const X = 0;
|
||||
// const X : integer = 0;
|
||||
PrevSibling:=nil;
|
||||
NextSibling:=nil;
|
||||
if (Node.PriorBrother<>nil) and (Node.PriorBrother.FirstChild=nil) then
|
||||
PrevSibling:=Node.PriorBrother;
|
||||
if (Node.FirstChild=nil) and (Node.NextBrother<>nil) then
|
||||
NextSibling:=Node.NextBrother;
|
||||
DeleteStartPos:=Node.StartPos;
|
||||
DeleteEndPos:=Node.StartPos+GetIdentLen(@Src[Node.StartPos]);
|
||||
if NextSibling<>nil then begin
|
||||
// var i, X, j: integer; -> var i, [X, ]j: integer;
|
||||
// var X, i: integer; -> var [X, ]i: integer;
|
||||
MoveCursorToCleanPos(Node.StartPos);
|
||||
ReadNextAtom;
|
||||
AtomIsIdentifier(true);
|
||||
if not ReadNextAtomIsChar(',') then RaiseCharExpectedButAtomFound(',');
|
||||
DeleteEndPos:=CurPos.EndPos;
|
||||
end else if PrevSibling<>nil then begin
|
||||
// var i, X: integer; -> var i[, X]: integer;
|
||||
MoveCursorToCleanPos(PrevSibling.StartPos);
|
||||
ReadNextAtom;
|
||||
AtomIsIdentifier(true);
|
||||
if not ReadNextAtomIsChar(',') then RaiseCharExpectedButAtomFound(',');
|
||||
DeleteStartPos:=CurPos.StartPos;
|
||||
end else begin
|
||||
// delete whole declaration
|
||||
if (Node.Parent.Desc in AllDefinitionSections)
|
||||
and (Node.PriorBrother=nil) and (Node.NextBrother=nil) then begin
|
||||
// delete whole section
|
||||
DeleteStartPos:=Node.Parent.StartPos;
|
||||
DeleteEndPos:=Node.Parent.EndPos;
|
||||
end else if Node.Parent.Desc=ctnParameterList then begin
|
||||
// delete whole parameter including modifier, type and default value
|
||||
if Node.PriorBrother<>nil then begin
|
||||
// ... var i: integer; var X: ... -> ... var i: integer[; var X: ...
|
||||
MoveCursorToCleanPos(Node.PriorBrother.EndPos);
|
||||
repeat
|
||||
ReadNextAtom;
|
||||
if CurPos.Flag=cafSemicolon then begin
|
||||
DeleteStartPos:=CurPos.EndPos;
|
||||
break;
|
||||
end;
|
||||
until CurPos.StartPos>=Node.StartPos;
|
||||
end else begin
|
||||
// (var X: ... -> ([; X: ...
|
||||
MoveCursorToCleanPos(Node.Parent.StartPos);
|
||||
ReadNextAtom;
|
||||
if CurPos.Flag in [cafRoundBracketOpen,cafEdgedBracketOpen] then
|
||||
DeleteStartPos:=CurPos.EndPos;
|
||||
end;
|
||||
if Node.NextBrother<>nil then begin
|
||||
// ... var X: integer; var i: ... -> .. var X: integer;] var i: ...
|
||||
DeleteEndPos:=Node.PriorBrother.EndPos;
|
||||
end else begin
|
||||
// ... var X: integer) -> .. var X: integer])
|
||||
DeleteEndPos:=Node.EndPos;
|
||||
end;
|
||||
end else begin
|
||||
// keep section, delete whole declaration
|
||||
DeleteEndPos:=Node.EndPos;
|
||||
end;
|
||||
end;
|
||||
// include corresponding comments
|
||||
DeleteFirstTokenOfLine:=FindFirstNonSpaceCharInLine(Src,DeleteStartPos)=DeleteStartPos;
|
||||
//DebugLn(['TStandardCodeTool.RemoveIdentifierDefinition ',dbgstr(copy(Src,FindFirstNonSpaceCharInLine(Src,DeleteStartPos),10))]);
|
||||
DeleteEndPos:=FindLineEndOrCodeAfterPosition(DeleteEndPos,true,DeleteFirstTokenOfLine);
|
||||
if DeleteFirstTokenOfLine and (Src[DeleteEndPos-1] in [#10,#13]) then begin
|
||||
// delete first and last token of line
|
||||
// => remove the entire line
|
||||
DeleteStartPos:=GetLineStartPosition(Src,DeleteStartPos);
|
||||
end;
|
||||
//DebugLn(['TStandardCodeTool.RemoveIdentifierDefinition "',dbgstr(copy(Src,DeleteStartPos,DeleteEndPos-DeleteStartPos)),'" IncludeLineEnd=',DeleteFirstTokenOfLine]);
|
||||
|
||||
// delete
|
||||
SourceChangeCache.MainScanner:=Scanner;
|
||||
if not SourceChangeCache.Replace(gtNone,gtNone,DeleteStartPos,DeleteEndPos,'')
|
||||
then exit;
|
||||
Result:=SourceChangeCache.Apply;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TStandardCodeTool.FindBlockCounterPart(
|
||||
const CursorPos: TCodeXYPosition;
|
||||
out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
|
||||
|
@ -4774,6 +4774,8 @@ resourcestring
|
||||
+'filename, the hostname with an optional username and the filename of '
|
||||
+'gdb on the remote computer. For example: %s/usr/bin/ssh username@'
|
||||
+'hostname gdb%s or: %s/usr/bin/setsid /usr/bin/ssh username@hostname gdb%s';
|
||||
lisRemoveUnitFromUsesSection = 'Remove unit from uses section';
|
||||
lisRemoveLocalVariable = 'Remove local variable %s';
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -83,6 +83,15 @@ type
|
||||
procedure Execute(const Msg: TIDEMessageLine; Step: TIMQuickFixStep); override;
|
||||
end;
|
||||
|
||||
{ TQuickFixLocalVariableNotUsed_Remove }
|
||||
|
||||
TQuickFixLocalVariableNotUsed_Remove = class(TIDEMsgQuickFixItem)
|
||||
public
|
||||
constructor Create;
|
||||
function IsApplicable(Line: TIDEMessageLine): boolean; override;
|
||||
procedure Execute(const Msg: TIDEMessageLine; Step: TIMQuickFixStep); override;
|
||||
end;
|
||||
|
||||
procedure QuickFixParameterNotUsed(Sender: TObject; Step: TIMQuickFixStep;
|
||||
Msg: TIDEMessageLine);
|
||||
procedure QuickFixUnitNotUsed(Sender: TObject; Step: TIMQuickFixStep;
|
||||
@ -96,6 +105,37 @@ procedure FreeStandardIDEQuickFixItems;
|
||||
|
||||
implementation
|
||||
|
||||
procedure ShowError(Msg: string);
|
||||
begin
|
||||
MessageDlg('QuickFix error',Msg,mtError,[mbCancel],0);
|
||||
end;
|
||||
|
||||
function IsIdentifierInCode(Code: TCodeBuffer; X,Y: integer;
|
||||
Identifier, ErrorMsg: string): boolean;
|
||||
var
|
||||
p: integer;
|
||||
IdentStart: integer;
|
||||
IdentEnd: integer;
|
||||
begin
|
||||
Result:=false;
|
||||
if Code=nil then begin
|
||||
ShowError(ErrorMsg+' (Code=nil)');
|
||||
exit;
|
||||
end;
|
||||
Code.LineColToPosition(Y,X,p);
|
||||
if p<1 then begin
|
||||
ShowError(ErrorMsg+' (position outside of source');
|
||||
exit;
|
||||
end;
|
||||
GetIdentStartEndAtPosition(Code.Source,p,IdentStart,IdentEnd);
|
||||
if SysUtils.CompareText(Identifier,copy(Code.Source,IdentStart,IdentEnd-IdentStart))<>0
|
||||
then begin
|
||||
ShowError(ErrorMsg);
|
||||
exit;
|
||||
end;
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
procedure QuickFixParameterNotUsed(Sender: TObject; Step: TIMQuickFixStep;
|
||||
Msg: TIDEMessageLine);
|
||||
begin
|
||||
@ -114,6 +154,7 @@ begin
|
||||
|
||||
if not REMatches(Msg.Msg,'Unit "([a-z_0-9]+)" not used','I') then begin
|
||||
DebugLn('QuickFixUnitNotUsed invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: UnitNotUsed invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
UnneededUnitname:=REVar(1);
|
||||
@ -181,6 +222,7 @@ begin
|
||||
RegisterIDEMsgQuickFix(TQuickFixLinkerUndefinedReference.Create);
|
||||
RegisterIDEMsgQuickFix(TQuickFixClassWithAbstractMethods.Create);
|
||||
RegisterIDEMsgQuickFix(TQuickFixIdentifierNotFoundAddLocal.Create);
|
||||
RegisterIDEMsgQuickFix(TQuickFixLocalVariableNotUsed_Remove.Create);
|
||||
end;
|
||||
|
||||
procedure FreeStandardIDEQuickFixItems;
|
||||
@ -219,6 +261,7 @@ begin
|
||||
|
||||
if not REMatches(Msg.Msg,'Can''t find unit ([a-z_0-9]+)','I') then begin
|
||||
DebugLn('QuickFixUnitNotFoundPosition invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: UnitNotFoundPosition invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
MissingUnitname:=REVar(1);
|
||||
@ -230,11 +273,13 @@ begin
|
||||
NewFilename:=LazarusIDE.FindUnitFile(UsedByUnit);
|
||||
if NewFilename='' then begin
|
||||
DebugLn('QuickFixUnitNotFoundPosition unit not found: ',UsedByUnit);
|
||||
ShowError('QuickFix: UnitNotFoundPosition unit not found: '+UsedByUnit);
|
||||
exit;
|
||||
end;
|
||||
CodeBuf:=CodeToolBoss.LoadFile(NewFilename,false,false);
|
||||
if CodeBuf=nil then begin
|
||||
DebugLn('QuickFixUnitNotFoundPosition unable to load unit: ',NewFilename);
|
||||
ShowError('QuickFix: UnitNotFoundPosition unable to load unit: '+NewFilename);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
@ -244,6 +289,7 @@ begin
|
||||
NamePos,InPos)
|
||||
then begin
|
||||
DebugLn('QuickFixUnitNotFoundPosition failed due to syntax errors or '+MissingUnitname+' is not used in '+CodeBuf.Filename);
|
||||
LazarusIDE.DoJumpToCodeToolBossError;
|
||||
exit;
|
||||
end;
|
||||
if InPos=0 then ;
|
||||
@ -277,13 +323,6 @@ procedure TQuickFixLinkerUndefinedReference.Execute(const Msg: TIDEMessageLine;
|
||||
unit1.o(.text+0x3a):unit1.pas:48: undefined reference to `DoesNotExist'
|
||||
}
|
||||
|
||||
procedure Error(const Msg: string);
|
||||
begin
|
||||
DebugLn('TQuickFixLinkerUndefinedReference.Execute ',Msg);
|
||||
MessageDlg('TQuickFixLinkerUndefinedReference.Execute',
|
||||
Msg,mtError,[mbCancel],0);
|
||||
end;
|
||||
|
||||
procedure JumpTo(Line1, Line2: TIDEMessageLine);
|
||||
var
|
||||
Identifier: String;
|
||||
@ -343,26 +382,22 @@ procedure TQuickFixLinkerUndefinedReference.Execute(const Msg: TIDEMessageLine;
|
||||
DebugLn(['TQuickFixLinkerUndefinedReference.JumpTo Filename="',Filename,'" MangledFunction="',MangledFunction,'" Identifier="',Identifier,'" SourceFilename="',SourceFilename,'" SourceLine=',SourceLine]);
|
||||
CurProject:=LazarusIDE.ActiveProject;
|
||||
if CurProject=nil then begin
|
||||
Error('no project');
|
||||
ShowError('QuickFix: LinkerUndefinedReference no project');
|
||||
exit;
|
||||
end;
|
||||
if (CurProject.MainFile=nil) then begin
|
||||
Error('no main file in project');
|
||||
exit;
|
||||
end;
|
||||
if (CurProject.MainFile=nil) then begin
|
||||
Error('no main file in project');
|
||||
ShowError('QuickFix: LinkerUndefinedReference no main file in project');
|
||||
exit;
|
||||
end;
|
||||
CodeBuf:=CodeToolBoss.LoadFile(CurProject.MainFile.Filename,true,false);
|
||||
if (CodeBuf=nil) then begin
|
||||
Error('project main file has no source');
|
||||
ShowError('QuickFix: LinkerUndefinedReference project main file has no source');
|
||||
exit;
|
||||
end;
|
||||
AnUnitName:=ExtractFilenameOnly(Filename);
|
||||
CodeBuf:=CodeToolBoss.FindUnitSource(CodeBuf,AnUnitName,'');
|
||||
if (CodeBuf=nil) then begin
|
||||
Error('unit not found: '+AnUnitName);
|
||||
ShowError('QuickFix: LinkerUndefinedReference unit not found: '+AnUnitName);
|
||||
exit;
|
||||
end;
|
||||
if not CodeToolBoss.JumpToLinkerIdentifier(CodeBuf,
|
||||
@ -372,7 +407,7 @@ procedure TQuickFixLinkerUndefinedReference.Execute(const Msg: TIDEMessageLine;
|
||||
if CodeToolBoss.ErrorCode<>nil then
|
||||
LazarusIDE.DoJumpToCodeToolBossError
|
||||
else
|
||||
Error('function not found: '+MangledFunction+' Identifier='+Identifier);
|
||||
ShowError('QuickFix: LinkerUndefinedReference function not found: '+MangledFunction+' Identifier='+Identifier);
|
||||
exit;
|
||||
end;
|
||||
LazarusIDE.DoOpenFileAndJumpToPos(NewCode.Filename,Point(NewX,NewY),
|
||||
@ -438,10 +473,11 @@ begin
|
||||
// get class name
|
||||
if not REMatches(Msg.Msg,'Warning: Constructing a class "([a-z_0-9]+)"','I') then begin
|
||||
DebugLn('QuickFixClassWithAbstractMethods invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: ClassWithAbstractMethods invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
CurClassName:=REVar(1);
|
||||
DebugLn(['TQuickFixClassWithAbstractMethods.Execute Class=',CurClassName]);
|
||||
//DebugLn(['TQuickFixClassWithAbstractMethods.Execute Class=',CurClassName]);
|
||||
|
||||
// find the class
|
||||
|
||||
@ -449,6 +485,7 @@ begin
|
||||
CodeToolBoss.Explore(CodeBuf,Tool,false,true);
|
||||
if Tool=nil then begin
|
||||
DebugLn(['TQuickFixClassWithAbstractMethods.Execute no tool for ',CodeBuf.Filename]);
|
||||
ShowError('QuickFix: ClassWithAbstractMethods no tool for '+CodeBuf.Filename);
|
||||
exit;
|
||||
end;
|
||||
|
||||
@ -465,12 +502,13 @@ begin
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
DebugLn(['TQuickFixClassWithAbstractMethods.Execute Declaration at ',NewCode.Filename,' ',NewX,',',NewY]);
|
||||
//DebugLn(['TQuickFixClassWithAbstractMethods.Execute Declaration at ',NewCode.Filename,' ',NewX,',',NewY]);
|
||||
|
||||
if LazarusIDE.DoOpenFileAndJumpToPos(NewCode.Filename,
|
||||
Point(NewX,NewY),NewTopLine,-1,-1,[])<>mrOk
|
||||
then begin
|
||||
DebugLn(['TQuickFixClassWithAbstractMethods.Execute failed opening ',NewCode.Filename]);
|
||||
ShowError('QuickFix: ClassWithAbstractMethods failed opening '+NewCode.Filename);
|
||||
exit;
|
||||
end;
|
||||
|
||||
@ -555,10 +593,17 @@ begin
|
||||
// get identifier
|
||||
if not REMatches(Msg.Msg,'Error: Identifier not found "([a-z_0-9]+)"','I') then begin
|
||||
DebugLn('TQuickFixIdentifierNotFoundAddLocal invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: IdentifierNotFoundAddLocal invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
Identifier:=REVar(1);
|
||||
DebugLn(['TQuickFixIdentifierNotFoundAddLocal.Execute Identifier=',Identifier]);
|
||||
//DebugLn(['TQuickFixIdentifierNotFoundAddLocal.Execute Identifier=',Identifier]);
|
||||
|
||||
if not IsIdentifierInCode(CodeBuf,Caret.X,Caret.Y,Identifier,
|
||||
Identifier+' not found in '+CodeBuf.Filename
|
||||
+' at line '+IntToStr(Caret.Y)+', column '+IntToStr(Caret.X)+'.'#13
|
||||
+'Maybe the message is outdated.')
|
||||
then exit;
|
||||
|
||||
if not CodeToolBoss.CreateVariableForIdentifier(CodeBuf,Caret.X,Caret.Y,-1,
|
||||
NewCode,NewX,NewY,NewTopLine)
|
||||
@ -577,7 +622,7 @@ end;
|
||||
constructor TQuickFixUnitNotFound_Remove.Create;
|
||||
begin
|
||||
Name:='Search unit: Error: Can''t find unit Name';
|
||||
Caption:='Remove unit from uses section';
|
||||
Caption:=lisRemoveUnitFromUsesSection;
|
||||
Steps:=[imqfoMenuItem];
|
||||
end;
|
||||
|
||||
@ -618,6 +663,7 @@ begin
|
||||
// get unitname
|
||||
if not REMatches(Msg.Msg,'Fatal: Can''t find unit ([a-z_0-9]+) ','I') then begin
|
||||
DebugLn('TQuickFixUnitNotFound_Remove invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: UnitNotFound_Remove invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
AnUnitName:=REVar(1);
|
||||
@ -625,6 +671,7 @@ begin
|
||||
|
||||
if (AnUnitName='') or (not IsValidIdent(AnUnitName)) then begin
|
||||
DebugLn(['TQuickFixUnitNotFound_Remove.Execute not an identifier "',dbgstr(AnUnitName),'"']);
|
||||
ShowError('QuickFix: UnitNotFound_Remove not an identifier "'+dbgstr(AnUnitName)+'"');
|
||||
exit;
|
||||
end;
|
||||
|
||||
@ -640,5 +687,88 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TQuickFixLocalVariableNotUsed_Remove }
|
||||
|
||||
constructor TQuickFixLocalVariableNotUsed_Remove.Create;
|
||||
begin
|
||||
Name:='Remove local variable: Note: Local variable "x" not used';
|
||||
Caption:='Remove local variable';
|
||||
Steps:=[imqfoMenuItem];
|
||||
end;
|
||||
|
||||
function TQuickFixLocalVariableNotUsed_Remove.IsApplicable(Line: TIDEMessageLine
|
||||
): boolean;
|
||||
const
|
||||
SearchStr1 = ') Note: Local variable "';
|
||||
SearchStr2 = '" not used';
|
||||
var
|
||||
Msg: String;
|
||||
StartPos: integer;
|
||||
p: LongInt;
|
||||
Variable: String;
|
||||
begin
|
||||
Result:=false;
|
||||
if (Line.Parts=nil) then exit;
|
||||
Msg:=Line.Msg;
|
||||
//DebugLn(['TQuickFixLocalVariableNotUsed_Remove.IsApplicable Msg="',Msg,'" ',System.Pos(SearchStr1,Msg),' ',System.Pos(SearchStr2,Msg)]);
|
||||
StartPos:=System.Pos(SearchStr1,Msg);
|
||||
if StartPos<1 then exit;
|
||||
inc(StartPos,length(SearchStr1));
|
||||
p:=StartPos;
|
||||
while (p<=length(Msg)) and (Msg[p]<>'"') do inc(p);
|
||||
if copy(Msg,p,length(SearchStr2))<>SearchStr2 then exit;
|
||||
Variable:=copy(Msg,StartPos,p-StartPos);
|
||||
if (Variable='') or not IsValidIdent(Variable) then exit;
|
||||
Caption:=Format(lisRemoveLocalVariable, [Variable]);
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
procedure TQuickFixLocalVariableNotUsed_Remove.Execute(
|
||||
const Msg: TIDEMessageLine; Step: TIMQuickFixStep);
|
||||
var
|
||||
CodeBuf: TCodeBuffer;
|
||||
Filename: string;
|
||||
Caret: TPoint;
|
||||
Variable: String;
|
||||
begin
|
||||
if Step=imqfoMenuItem then begin
|
||||
DebugLn(['TQuickFixLocalVariableNotUsed_Remove.Execute ']);
|
||||
// get source position
|
||||
if not GetMsgLineFilename(Msg,CodeBuf) then exit;
|
||||
Msg.GetSourcePosition(Filename,Caret.Y,Caret.X);
|
||||
if not LazarusIDE.BeginCodeTools then begin
|
||||
DebugLn(['TQuickFixLocalVariableNotUsed_Remove.Execute failed because IDE busy']);
|
||||
exit;
|
||||
end;
|
||||
|
||||
// get variables name
|
||||
if not REMatches(Msg.Msg,'Note: Local variable "([a-z_0-9]+)" not used','I')
|
||||
then begin
|
||||
DebugLn('TQuickFixLocalVariableNotUsed_Remove invalid message ',Msg.Msg);
|
||||
ShowError('QuickFix: LocalVariableNotUsed_Remove invalid message '+Msg.Msg);
|
||||
exit;
|
||||
end;
|
||||
Variable:=REVar(1);
|
||||
//DebugLn(['TQuickFixLocalVariableNotUsed_Remove.Execute Variable=',Variable]);
|
||||
|
||||
// check if the variable is at that position
|
||||
if not IsIdentifierInCode(CodeBuf,Caret.X,Caret.Y,Variable,
|
||||
Variable+' not found in '+CodeBuf.Filename
|
||||
+' at line '+IntToStr(Caret.Y)+', column '+IntToStr(Caret.X)+'.'#13
|
||||
+'Maybe the message is outdated.')
|
||||
then exit;
|
||||
|
||||
if not CodeToolBoss.RemoveIdentifierDefinition(CodeBuf,Caret.X,Caret.Y) then
|
||||
begin
|
||||
DebugLn(['TQuickFixLocalVariableNotUsed_Remove.Execute remove failed']);
|
||||
LazarusIDE.DoJumpToCodeToolBossError;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// message fixed -> clean
|
||||
Msg.Msg:='';
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user