Delphi XE2:调试器偏移7-20行,编译器错误行号也偏移同样数量

14

我在工作中遇到了一个大型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用户界面的一部分),然后单击“下载”以下载它。


1
如果您添加(或删除)了代码行并按F9键,则可能二进制文件中使用的DCU(因此调试器的标记)尚未重新构建(我遇到过这个问题很多次)。在这种情况下,我只需执行“清理”然后“构建”,问题就会消失。您试过了吗? - LaKraven
1
PS - 当我调试 SQL Server 脚本中的错误(非常大,例如单个文件有 20k 行)时,我会遇到完全相同的问题。 - Jerry Dodge
1
(即SQL Server Management Studio 2008 R2) - Jerry Dodge
2
Lakraven;清理和重建没有效果。行结束符答案似乎合理可信。 - Warren P
我曾经有这样的经验,当我的\Windows\system32文件夹中有xe2u2版本的rtl.bpl和vcl.bpl时,我在Delphi上安装了更新#4 - 因此程序(和调试信息)是针对更新的BPL/DCP文件编译的,并在实际执行时加载。 - Arioch 'The
显示剩余8条评论
3个回答

23

我以前见过这样的情况,根据我的经验通常是由于编译器计数行号时出现错误导致的。如果你有非标准的换行符(不是CRLF)在某些地方 - 这种情况可能会发生 - IDE将进行适当的换行,但编译器不会将它们计算为新行,所以之后的所有内容都会偏移一个位置。

当我遇到这样的文件时,我会在EditPad中打开它,将所有换行符转换为其他风格(Unix或Mac风格),然后将所有换行符转换为Windows风格并保存它。这可以确保文件中的每一行都以CRLF结尾,在重新构建后,蓝点没有正确对齐的问题就消失了。


这在Visual Studio中也会发生。我使用CodeRush,它会警告我任何具有混合行结尾的文件,并提供将它们转换为一种风格的选项。 - Jeroen Wiert Pluimers
1
我写了一个小工具来帮助解决问题,并将其附加到上面的答案中。如果对人们有用,我会写一些更加仔细的东西并将其开源。 - Warren P
确认无误。在运行我在答案中发布的代码后,我再也无法重现这些问题了。做得好。感谢你们两位抽出时间来回答。 - Warren P
如果有人需要扫描他们的代码,可以查看更新问题中的链接,我写了一个实用程序。(如果传入正确的参数,它也会修复它,但默认情况下要小心,它只读取内容而不写入内容。) - Warren P

10

这是一个由于行终止符不匹配引起的常见问题(代码中缺少回车或换行符)。它也可能是由于打开编辑器中的源文件与不匹配的.dcu文件引起的。

对于第一种情况,最简单的解决方法是在普通文本编辑器(如记事本)中打开源文件。进行一些小修改(插入空行然后删除),然后保存文件。记事本将会修复行末尾符号。

如果这不是问题的原因,请查找驱动器中IDE搜索路径中可能存在的.dcu(或.pas)文件的额外副本。有时编译器看到的版本与编辑器中打开的版本不同。


5
我们不得不使用第三方工具来解决那些愚蠢的小 IDE 和编译器错误,这很令人沮丧。理论上这些问题都应该直接处理。 - Jerry Dodge
1
@Jerry:这不仅是Delphi IDE的问题。Visual Studio也有此问题(主要是因为人们在其中打开*nix文件),并在编辑器上下文菜单中提供“规范化行结尾”选项来修复它。(例如,请参见我发布此答案的问题。)当从某些浏览器的网页中复制/粘贴代码到IDE代码编辑器时,这也经常发生。 - Ken White
1
说到这个:http://meta.stackexchange.com/questions/169766/code-not-formatted-as-code - Jerry Dodge
就此而言:记事本经常在我的系统上(从NT 4到Windows 8)出现非标准行尾时出现错误。通常我会使用SourcePad进行更正,或者使用一个简单的unix2dos工具。http://en.wikipedia.org/wiki/Unix2dos - Jeroen Wiert Pluimers
1
现在你可以使用我的方便易用的递归下降修复工具。 - Warren P
显示剩余5条评论

0

这绝对与之前的帖子中解释的行结尾有关。 试图编辑它是非常困难的,因为Embarcadero编辑器试图进行自己的魔法并保留当前部分的行结尾(或者看起来是这样)。

解决方案: 在IDE编辑器窗口中右键单击,选择“格式化源”(Ctrl-D)并接受。

这将修复所有行结尾并消除问题(对我来说是这样)。 作为副产品,您将获得正确格式的源代码:-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接