diff --git a/components/codetools/codetoolmanager.pas b/components/codetools/codetoolmanager.pas index 84cd9247eb..7aafcde2ad 100644 --- a/components/codetools/codetoolmanager.pas +++ b/components/codetools/codetoolmanager.pas @@ -893,15 +893,23 @@ end; function TCodeToolManager.HandleException(AnException: Exception): boolean; var ErrorSrcTool: TCustomCodeTool; + DirtyPos: Integer; begin fErrorMsg:=AnException.Message; fErrorTopLine:=0; if (AnException is ELinkScannerError) then begin - // linker error - fErrorCode:=TCodeBuffer(ELinkScannerError(AnException).Sender.Code); - if fErrorCode<>nil then begin - fErrorCode.AbsoluteToLineCol( - ELinkScannerError(AnException).Sender.SrcPos,fErrorLine,fErrorColumn); + // link scanner error + DirtyPos:=0; + if AnException is ELinkScannerEditError then begin + fErrorCode:=TCodeBuffer(ELinkScannerEditError(AnException).Buffer); + if fErrorCode<>nil then + DirtyPos:=ELinkScannerEditError(AnException).BufferPos; + end else begin + fErrorCode:=TCodeBuffer(ELinkScannerError(AnException).Sender.Code); + DirtyPos:=ELinkScannerError(AnException).Sender.SrcPos; + end; + if (fErrorCode<>nil) and (DirtyPos>0) then begin + fErrorCode.AbsoluteToLineCol(DirtyPos,fErrorLine,fErrorColumn); end; end else if (AnException is ECodeToolError) then begin // codetool error @@ -909,6 +917,9 @@ begin fErrorCode:=ErrorSrcTool.ErrorPosition.Code; fErrorColumn:=ErrorSrcTool.ErrorPosition.X; fErrorLine:=ErrorSrcTool.ErrorPosition.Y; + end else if (AnException is ESourceChangeCacheError) then begin + // SourceChangeCache error + fErrorCode:=nil; end else begin // unknown exception FErrorMsg:=AnException.ClassName+': '+FErrorMsg; diff --git a/components/codetools/codetoolsstrconsts.pas b/components/codetools/codetoolsstrconsts.pas index eba40434f1..041e7c2d7e 100644 --- a/components/codetools/codetoolsstrconsts.pas +++ b/components/codetools/codetoolsstrconsts.pas @@ -46,6 +46,7 @@ ResourceString ctsIncludeFileNotFound = 'include file not found "%s"'; ctsErrorInDirectiveExpression = 'error in directive expression'; ctsIncludeCircleDetected = 'Include circle detected'; + ctsfileIsReadOnly = 'file is read only'; ctsCommentEndNotFound = 'Comment end not found'; // customcodetool diff --git a/components/codetools/linkscanner.pas b/components/codetools/linkscanner.pas index cda84ddfd8..af1de3c009 100644 --- a/components/codetools/linkscanner.pas +++ b/components/codetools/linkscanner.pas @@ -138,6 +138,13 @@ type ELinkScannerAbort = class(ELinkScannerError) end; + + ELinkScannerEditError = class(ELinkScannerError) + Buffer: Pointer; + BufferPos: integer; + constructor Create(ASender: TLinkScanner; const AMessage: string; + ABuffer: Pointer; ABufferPos: integer); + end; { TLinkScanner } @@ -264,10 +271,12 @@ type LastErrorBehindIgnorePosition: boolean; LastErrorCheckedForIgnored: boolean; CleanedIgnoreErrorAfterPosition: integer; - procedure RaiseExceptionFmt(const AMessage: string; args: array of const); + procedure RaiseExceptionFmt(const AMessage: string; Args: array of const); procedure RaiseException(const AMessage: string); procedure RaiseExceptionClass(const AMessage: string; ExceptionClass: ELinkScannerErrors); + procedure RaiseEditException(const AMessage: string; ABuffer: Pointer; + ABufferPos: integer); procedure ClearLastError; procedure RaiseLastError; procedure DoCheckAbort; @@ -311,7 +320,8 @@ type procedure RaiseLastErrorIfInFrontOfCleanedPos(ACleanedPos: integer); // ranges - function WholeRangeIsWritable(CleanStartPos, CleanEndPos: integer): boolean; + function WholeRangeIsWritable(CleanStartPos, CleanEndPos: integer; + ErrorOnFail: boolean): boolean; procedure FindCodeInRange(CleanStartPos, CleanEndPos: integer; UniqueSortedCodeList: TList); procedure DeleteRange(CleanStartPos,CleanEndPos: integer); @@ -2780,20 +2790,37 @@ begin end; end; -function TLinkScanner.WholeRangeIsWritable(CleanStartPos, CleanEndPos: integer - ): boolean; -var ACode: Pointer; +function TLinkScanner.WholeRangeIsWritable(CleanStartPos, CleanEndPos: integer; + ErrorOnFail: boolean): boolean; + + procedure EditError(const AMessage: string; ACode: Pointer); + begin + if ErrorOnFail then + RaiseEditException(AMessage,ACode,0); + end; + +var + ACode: Pointer; LinkIndex: integer; CodeIsReadOnly: boolean; begin Result:=false; if (CleanStartPos<1) or (CleanStartPos>=CleanEndPos) - or (CleanEndPos>CleanedLen+1) or (not Assigned(FOnGetSourceStatus)) then exit; + or (CleanEndPos>CleanedLen+1) or (not Assigned(FOnGetSourceStatus)) then begin + EditError('TLinkScanner.WholeRangeIsWritable: Invalid range',nil); + exit; + end; LinkIndex:=LinkIndexAtCleanPos(CleanStartPos); - if LinkIndex<0 then exit; + if LinkIndex<0 then begin + EditError('TLinkScanner.WholeRangeIsWritable: position out of scan range',nil); + exit; + end; ACode:=FLinks[LinkIndex].Code; FOnGetSourceStatus(Self,ACode,CodeIsReadOnly); - if CodeIsReadOnly then exit; + if CodeIsReadOnly then begin + EditError(ctsfileIsReadOnly, ACode); + exit; + end; repeat inc(LinkIndex); if (LinkIndex>=LinkCount) or (FLinks[LinkIndex].CleanedPos>CleanEndPos) then @@ -2804,7 +2831,10 @@ begin if ACode<>FLinks[LinkIndex].Code then begin ACode:=FLinks[LinkIndex].Code; FOnGetSourceStatus(Self,ACode,CodeIsReadOnly); - if CodeIsReadOnly then exit; + if CodeIsReadOnly then begin + EditError(ctsfileIsReadOnly, ACode); + exit; + end; end; until false; end; @@ -2892,6 +2922,12 @@ begin raise ExceptionClass.Create(Self,AMessage); end; +procedure TLinkScanner.RaiseEditException(const AMessage: string; + ABuffer: Pointer; ABufferPos: integer); +begin + raise ELinkScannerEditError.Create(Self,AMessage,ABuffer,ABufferPos); +end; + procedure TLinkScanner.ClearLastError; begin LastErrorIsValid:=false; @@ -3094,6 +3130,16 @@ begin PSourceLinkMemManager.Free; end; +{ ELinkScannerEditError } + +constructor ELinkScannerEditError.Create(ASender: TLinkScanner; + const AMessage: string; ABuffer: Pointer; ABufferPos: integer); +begin + inherited Create(ASender,AMessage); + Buffer:=ABuffer; + BufferPos:=ABufferPos; +end; + initialization InternalInit; diff --git a/components/codetools/sourcechanger.pas b/components/codetools/sourcechanger.pas index c7c54fa299..e268a783ec 100644 --- a/components/codetools/sourcechanger.pas +++ b/components/codetools/sourcechanger.pas @@ -42,8 +42,8 @@ interface { $DEFINE CTDEBUG} uses - Classes, SysUtils, CodeCache, BasicCodeTools, SourceLog, LinkScanner, - AVL_Tree, KeywordFuncLists; + Classes, SysUtils, CodeToolsStrConsts, CodeCache, BasicCodeTools, SourceLog, + LinkScanner, AVL_Tree, KeywordFuncLists; type { TBeautifyCodeOptions } @@ -130,6 +130,9 @@ type constructor Create; end; + + { TSourceChangeCache } + //---------------------------------------------------------------------------- // in front of and after a text change can be set a gap. // A Gap is for example a space char or a newline. TSourceChangeLog will add @@ -139,7 +142,6 @@ type gtNewLine, // at least a newline gtEmptyLine // at least two newlines ); - TSourceChangeCacheEntry = class public @@ -180,6 +182,8 @@ type procedure SetMainScanner(NewScanner: TLinkScanner); function GetBuffersToModify(Index: integer): TCodeBuffer; procedure UpdateBuffersToModify; + protected + procedure RaiseException(const AMessage: string); public BeautifyCodeOptions: TBeautifyCodeOptions; procedure BeginUpdate; @@ -207,6 +211,15 @@ type constructor Create; destructor Destroy; override; end; + + { ESourceChangeCacheError } + + ESourceChangeCacheError = class(Exception) + public + Sender: TSourceChangeCache; + constructor Create(ASender: TSourceChangeCache; const AMessage: string); + end; + const AtomTypeNames: array[TAtomType] of shortstring = ( @@ -412,6 +425,35 @@ function TSourceChangeCache.ReplaceEx(FrontGap, AfterGap: TGapTyp; FromPos, ToPos: integer; DirectCode: TCodeBuffer; FromDirectPos, ToDirectPos: integer; const Text: string): boolean; + + procedure RaiseDataInvalid; + begin + if MainScanner=nil then + RaiseException('TSourceChangeCache.ReplaceEx MainScanner=nil'); + if FromPos>ToPos then + RaiseException('TSourceChangeCache.ReplaceEx FromPos>ToPos'); + if FromPos<1 then + RaiseException('TSourceChangeCache.ReplaceEx FromPos<1'); + if ToPos>MainScanner.CleanedLen+1 then + RaiseException('TSourceChangeCache.ReplaceEx ToPos>MainScanner.CleanedLen+1'); + end; + + procedure RaiseIntersectionFound; + begin + RaiseException('TSourceChangeCache.ReplaceEx ' + +'IGNORED, because intersection found'); + end; + + procedure RaiseCodeReadOnly(Buffer: TCodeBuffer); + begin + RaiseException(ctsfileIsReadOnly+' '+Buffer.Filename); + end; + + procedure RaiseNotInCleanCode; + begin + RaiseException('TSourceChangeCache.ReplaceEx not in clean code'); + end; + var NewEntry: TSourceChangeCacheEntry; p: pointer; @@ -441,6 +483,7 @@ begin {$IFDEF CTDEBUG} writeln('TSourceChangeCache.ReplaceEx IGNORED, because data invalid'); {$ENDIF} + RaiseDataInvalid; exit; end; end else begin @@ -457,21 +500,24 @@ begin IntersectionEntry.FromPos,'-',IntersectionEntry.ToPos, ' IsDelete=',IntersectionEntry.IsDeleteOperation); {$ENDIF} + RaiseIntersectionFound; exit; end; if ToPos>FromPos then begin // this is a delete operation -> check the whole range for writable buffers - if not MainScanner.WholeRangeIsWritable(FromPos,ToPos) then exit; + if not MainScanner.WholeRangeIsWritable(FromPos,ToPos,true) then exit; end else if (DirectCode<>nil) and (FromDirectPos check if the DirectCode is writable - if DirectCode.ReadOnly then exit; + if DirectCode.ReadOnly then + RaiseCodeReadOnly(DirectCode); end; if DirectCode=nil then begin if not MainScanner.CleanedPosToCursor(FromPos,FromDirectPos,p) then begin {$IFDEF CTDEBUG} writeln('TSourceChangeCache.ReplaceEx IGNORED, because not in clean pos'); {$ENDIF} + RaiseNotInCleanCode; exit; end; DirectCode:=TCodeBuffer(p); @@ -831,6 +877,11 @@ begin FBuffersToModifyNeedsUpdate:=false; end; +procedure TSourceChangeCache.RaiseException(const AMessage: string); +begin + raise ESourceChangeCacheError.Create(Self,AMessage); +end; + { TBeautifyCodeOptions } constructor TBeautifyCodeOptions.Create; @@ -1237,6 +1288,14 @@ begin end; +{ ESourceChangeCacheError } + +constructor ESourceChangeCacheError.Create(ASender: TSourceChangeCache; + const AMessage: string); +begin + inherited Create(AMessage); + Sender:=ASender; +end; end. diff --git a/components/codetools/stdcodetools.pas b/components/codetools/stdcodetools.pas index c1e08e1982..0e88465afa 100644 --- a/components/codetools/stdcodetools.pas +++ b/components/codetools/stdcodetools.pas @@ -2688,7 +2688,8 @@ function TStandardCodeTool.RenamePublishedVariable(const UpperClassName, UpperOldVarName: string; const NewVarName, VarType: shortstring; ExceptionOnClassNotFound: boolean; SourceChangeCache: TSourceChangeCache): boolean; -var TypeNode, VarNode: TCodeTreeNode; +var + TypeNode, VarNode: TCodeTreeNode; begin Result:=false; VarNode:=FindPublishedVariable(UpperClassName,UpperOldVarName,