我在工作中遇到了一个大型Delphi代码库的问题,由于从Delphi 2007转移到XE2的副作用,我们现在遇到了以下奇怪但相关的问题:
即使在调试版本中,由于行号混乱,您无法设置断点或逐行调试代码,而且只有在某些单元中出现此问题。
故意在第2010行引入语法错误将导致光标聚焦于第2020行左右,偏差为3或4行,类似于这样:
.
procedure Correct;
begin
DoSomething; // syntax error reported HERE but the real error is below.
// more stuff here.
end;
procedure OllKorrect;
begin
ThisLineIsFine();
__VARIABLE_NOT_DEFINED__ := 1; // intentional error
end
我希望有人以前看过这个。问题的元素可能包括:
代码包含许多奇怪的编译器指令,如{$REALCOMPATIBILITY ON}和{$H-}/{$H+}指令,在代码中有成千上万的{$H+}/{$H-}指令。
其次,该代码使用了大量的{$I INCLUDE}指令,我怀疑包含文件可能直接搞乱了编译器的行号。
我无法确定,但我认为所有这些旧的“使其像DOS下的Turbo Pascal一样工作”的编译器开关是原因。它只发生在代码的某些地方,对于一个拥有超过500个单元的项目,其中一些单元达到10K / 20KLOC,这肯定是令人沮丧的。我可以说的是,不仅具有{$I include.inc}指令的单元会出现问题,而且许多包含大量{$H-}/{$H+}或{$REALCOMPATIBILITY}指令的单元也没有此问题。如果我能看到表现异常的单元有共同点,我就可以解决这个问题。
更新:行终止问题是有道理的。我运行了这段代码来检测问题。修复代码被注释掉了,因为如果你取消注释并清除了你的源代码,那就是你的问题。 它将非Unicode文件加载到Unicode TStringList中并将其保存回来。在我的世界里没问题,因为这一切都有版本控制和备份。您的情况可能会有所不同。
program linefeedsProject1;
{$APPTYPE CONSOLE}
uses
IOUtils,
Classes,
Types,
SysUtils;
var
broken,notBroken:Integer;
function fix(filename:String):Boolean;
var
sl:TStringList;
begin
sl := TStringList.Create;
try
sl.LoadFromFile(filename);
//TODO:Change file extensions.
sl.SaveToFile(filename);
finally
sl.Free;
end;
end;
function scan(filename:String):Boolean;
var
crFlag:Boolean;
lfFlag:Boolean;
missingCr:Integer;
missingLf:Integer;
f:TFileStream;
buf:Array[0..1024] of AnsiChar;
n:Integer;
procedure scanChars;
var
i:Integer;
begin
for i := 0 to n-1 do
begin
if buf[i]=#13 then
begin
crFlag := true;
lfFlag := false;
end
else if buf[i]=#10 then
begin
if not crFlag then
inc(missingCr);
lfFlag := true;
crFlag := false;
end
else begin
if (crFlag) then
inc(missingLf);
crFlag := false;
lfFlag := false;
end;
end;
end;
begin
result := false;
crFlag := false;
lfFlag := false;
missingCr := 0;
missingLf := 0;
f := TFileStream.Create(filename, fmOpenRead);
try
while f.Position< f.Size do
begin
n := f.Read(buf[0],1024);
scanChars;
end;
if (missingCr>0) or (missingLf>0) then
begin
WriteLn(' ', filename);
Inc(broken);
result := true;
end
else
begin
Inc(notBroken);
end
finally
f.Free;
end;
end;
var
files:TStringDynArray;
afile:String;
begin
try
broken := 0;
notBroken := 0;
files := TDirectory.GetFiles('C:\dev\abackupcopyofyoursourcecode', '*.pas',
TSearchOption.soTopDirectoryOnly );
// tried TSearchOption.soAllDirectories and it exploded. not recommended.
for afile in files do
begin
if scan(afile) then
begin
// fix(afile); // uncomment at your own risk and only on a backup copy of your code.
end;
end;
WriteLn('Broken ', broken);
WriteLn('not broken ',notBroken);
// readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
更新2:如果您需要此问题的扫描程序/修复程序,可以在此处下载我的程序(包含源代码)。 链接是Google Drive。您可以从链接中查看源代码,但请点击“文件”下拉菜单(Google Drive Web用户界面的一部分),然后单击“下载”以下载它。