Browse Source

pas2js: check duplicate files

git-svn-id: trunk@38047 -
Mattias Gaertner 7 years ago
parent
commit
9d6c109303
2 changed files with 135 additions and 34 deletions
  1. 14 7
      packages/pastojs/src/pas2jscompiler.pp
  2. 121 27
      packages/pastojs/src/pas2jsfilecache.pp

+ 14 - 7
packages/pastojs/src/pas2jscompiler.pp

@@ -946,6 +946,16 @@ begin
     HandleEPasResolve(EPasResolve(E))
   else if E is EPas2JS then
     HandleEPas2JS(EPas2JS(E))
+  else if E is EFileNotFoundError then
+  begin
+    Log.Log(mtFatal,E.Message);
+    Compiler.Terminate(ExitCodeFileNotFound);
+  end
+  else if E is EPas2jsFileCache then
+  begin
+    Log.Log(mtFatal,E.Message);
+    Compiler.Terminate(ExitCodeFileNotFound);
+  end
   else
     HandleUnknownException(E);
 end;
@@ -996,11 +1006,8 @@ begin
   try
     Scanner.OpenFile(PasFilename);
   except
-    on E: EScannerError do begin
-      Log.Log(Scanner.LastMsgType,Scanner.LastMsg,Scanner.LastMsgNumber,
-              Scanner.CurFilename,Scanner.CurRow,Scanner.CurColumn);
-      Compiler.Terminate(ExitCodeSyntaxError);
-    end;
+    on E: Exception do
+      HandleException(E);
   end;
 end;
 
@@ -2367,9 +2374,9 @@ begin
                 Delete(aFilename,length(aFilename),1);
                 if aFilename='' then
                   UnknownParam;
-                FileCache.RemoveInsertFilename(aFilename);
+                FileCache.RemoveInsertJSFilename(aFilename);
               end else
-                FileCache.AddInsertFilename(aFilename);
+                FileCache.AddInsertJSFilename(aFilename);
             end;
           'l': SetOption(coLowerCase,p^<>'-');
           'm':

+ 121 - 27
packages/pastojs/src/pas2jsfilecache.pp

@@ -21,6 +21,7 @@ const // Messages
   nUnitSearch = 202; sUnitSearch = 'Unitsearch: %s';
   nSearchingFileFound = 203; sSearchingFileFound = 'Searching file: %s... found';
   nSearchingFileNotFound = 204; sSearchingFileNotFound = 'Searching file: %s... not found';
+  nDuplicateFileFound = 205; sDuplicateFileFound = 'Duplicate file found: "%s" and "%s"';
 
 const
   PrecompiledExt = 'pju';
@@ -83,6 +84,8 @@ type
     function IndexOfFileCaseInsensitive(const ShortFilename: String): integer;
     function IndexOfFileCaseSensitive(const ShortFilename: String): integer;
     function IndexOfFile(const ShortFilename: String): integer; inline;
+    function CountSameNamesCaseInsensitive(Index: integer): integer;
+    procedure GetSameNamesCaseInsensitive(Index: integer; List: TStrings);
     property Entries[Index: integer]: TPas2jsCachedDirectoryEntry read GetEntries; default;
     procedure GetFiles(var Files: TStrings;
       IncludeDirs: boolean = true // add faDirectory as well
@@ -122,7 +125,7 @@ type
     procedure Clear;
     function DirectoryExists(Filename: string): boolean;
     function FileExists(Filename: string): boolean;
-    function FileExistsI(var Filename: string): boolean;
+    function FileExistsI(var Filename: string): integer; // returns number of found files
     function FileAge(Filename: string): TPas2jsFileAgeTime;
     function FileAttr(Filename: string): TPas2jsFileAttr;
     function FileSize(Filename: string): TPas2jsFileSize;
@@ -174,7 +177,7 @@ type
     function FindUnitJSFileName(const aUnitFilename: string): String;
     function FindCustomJSFileName(const aFilename: string): String;
     function FileExistsLogged(const Filename: string): boolean;
-    function FileExistsILogged(var Filename: string): boolean;
+    function FileExistsILogged(var Filename: string): integer;
     function SearchLowUpCase(var Filename: string): boolean; virtual;
     property Cache: TPas2jsFilesCache read FCache;
   end;
@@ -299,11 +302,12 @@ type
     function LoadTextFile(Filename: string): TPas2jsCachedFile;
     function NormalizeFilename(const Filename: string; RaiseOnError: boolean): string;
     procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
-    function IndexOfInsertFilename(const aFilename: string): integer;
-    procedure AddInsertFilename(const aFilename: string);
-    procedure RemoveInsertFilename(const aFilename: string);
+    function IndexOfInsertJSFilename(const aFilename: string): integer;
+    procedure AddInsertJSFilename(const aFilename: string);
+    procedure RemoveInsertJSFilename(const aFilename: string);
     procedure GetListing(const aDirectory: string; var Files: TStrings;
                          FullPaths: boolean = true);
+    procedure RaiseDuplicateFile(aFilename: string);
   public
     property AllJSIntoMainJS: Boolean read GetAllJSIntoMainJS write SetAllJSIntoMainJS;
     property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; // includes trailing pathdelim
@@ -562,7 +566,7 @@ end;
 procedure TPas2jsCachedDirectory.Release;
 begin
   if FRefCount<1 then
-    raise Exception.Create('TPas2jsCachedDirectory.Release "'+Path+'"');
+    raise Exception.Create('TPas2jsCachedDirectory.Release [20180126090800] "'+Path+'"');
   dec(FRefCount);
   if FRefCount=0 then Free;
 end;
@@ -689,6 +693,46 @@ begin
   {$ENDIF}
 end;
 
+function TPas2jsCachedDirectory.CountSameNamesCaseInsensitive(Index: integer
+  ): integer;
+var
+  i: Integer;
+  Filename: String;
+begin
+  Filename:=Entries[Index].Name;
+  Result:=1;
+  for i:=Index-1 downto 0 do
+  begin
+    if CompareText(Entries[i].Name,Filename)<>0 then break;
+    inc(Result);
+  end;
+  for i:=Index+1 to Count-1 do
+  begin
+    if CompareText(Entries[i].Name,Filename)<>0 then break;
+    inc(Result);
+  end;
+end;
+
+procedure TPas2jsCachedDirectory.GetSameNamesCaseInsensitive(Index: integer;
+  List: TStrings);
+var
+  i: Integer;
+  Filename: String;
+begin
+  Filename:=Entries[Index].Name;
+  List.Add(Filename);
+  for i:=Index-1 downto 0 do
+  begin
+    if CompareText(Entries[i].Name,Filename)<>0 then break;
+    List.Add(Entries[i].Name);
+  end;
+  for i:=Index+1 to Count-1 do
+  begin
+    if CompareText(Entries[i].Name,Filename)<>0 then break;
+    List.Add(Entries[i].Name);
+  end;
+end;
+
 procedure TPas2jsCachedDirectory.GetFiles(var Files: TStrings;
   IncludeDirs: boolean);
 var
@@ -810,7 +854,7 @@ begin
   while Node<>nil do begin
     Dir:=TPas2jsCachedDirectory(Node.Data);
     if Dir.FRefCount<>1 then
-      raise Exception.Create('TPas2jsCachedDirectories.Clear "'+Dir.Path+'" '+IntToStr(Dir.FRefCount));
+      raise Exception.Create('TPas2jsCachedDirectories.Clear [20180126090807] "'+Dir.Path+'" '+IntToStr(Dir.FRefCount));
     Dir.Release;
     Node.Data:=nil;
     Node:=FDirectories.FindSuccessor(Node);
@@ -842,21 +886,26 @@ begin
     Result:=SysUtils.FileExists(Info.Filename);
 end;
 
-function TPas2jsCachedDirectories.FileExistsI(var Filename: string): boolean;
+function TPas2jsCachedDirectories.FileExistsI(var Filename: string): integer;
 var
   Info: TFileInfo;
   i: Integer;
 begin
+  Result:=0;
   Info.Filename:=Filename;
-  if not GetFileInfo(Info) then exit(false);
+  if not GetFileInfo(Info) then exit;
   if Info.Dir=nil then
-    Result:=SysUtils.FileExists(Info.Filename)
+  begin
+    if SysUtils.FileExists(Info.Filename) then
+      Result:=1;
+  end
   else
   begin
     i:=Info.Dir.IndexOfFileCaseInsensitive(Info.ShortFilename);
-    Result:=i>=0;
-    if Result then
-      Filename:=ExtractFilePath(Filename)+Info.Dir[i].Name;
+    if i<0 then
+      exit;
+    Filename:=Info.Dir.Path+Info.Dir[i].Name;
+    Result:=Info.Dir.CountSameNamesCaseInsensitive(i);
   end;
 end;
 
@@ -963,7 +1012,7 @@ end;
 
 constructor TPas2jsFileLineReader.Create(const AFilename: string);
 begin
-  raise Exception.Create('TPas2jsFileLineReader.Create no cache "'+AFilename+'"');
+  raise Exception.Create('TPas2jsFileLineReader.Create [20180126090825] no cache "'+AFilename+'"');
 end;
 
 constructor TPas2jsFileLineReader.Create(aFile: TPas2jsCachedFile);
@@ -1191,13 +1240,19 @@ function TPas2jsFileResolver.FindSourceFile(const aFilename: string): TLineReade
 var
   CurFilename: String;
   Found: Boolean;
+  i: Integer;
 begin
   Result:=nil;
   CurFilename:=aFilename;
-  if Cache.SearchLikeFPC then
+  if StrictFileCase or Cache.SearchLikeFPC then
     Found:=Cache.DirectoryCache.FileExists(CurFilename)
   else
-    Found:=Cache.DirectoryCache.FileExistsI(CurFilename);
+  begin
+    i:=Cache.DirectoryCache.FileExistsI(CurFilename);
+    Found:=i=1;
+    if i>1 then
+      Cache.RaiseDuplicateFile(CurFilename);
+  end;
   if not Found then
     raise EFileNotFoundError.Create(aFilename)
   else
@@ -1325,11 +1380,11 @@ begin
       Cache.Log.LogMsgIgnoreFilter(nSearchingFileNotFound,[Cache.FormatPath(Filename)]);
 end;
 
-function TPas2jsFileResolver.FileExistsILogged(var Filename: string): boolean;
+function TPas2jsFileResolver.FileExistsILogged(var Filename: string): integer;
 begin
   Result:=Cache.DirectoryCache.FileExistsI(Filename);
   if Cache.ShowTriedUsedFiles then
-    if Result then
+    if Result>0 then
       Cache.Log.LogMsgIgnoreFilter(nSearchingFileFound,[Cache.FormatPath(Filename)])
     else
       Cache.Log.LogMsgIgnoreFilter(nSearchingFileNotFound,[Cache.FormatPath(Filename)]);
@@ -1339,6 +1394,7 @@ function TPas2jsFileResolver.SearchLowUpCase(var Filename: string): boolean;
 {$IFNDEF CaseInsensitiveFilenames}
 var
   CasedFilename: String;
+  i: Integer;
 {$ENDIF}
 begin
   if StrictFileCase or Cache.SearchLikeFPC then
@@ -1366,8 +1422,10 @@ begin
   end else
   begin
     // search case insensitive
-    if FileExistsILogged(Filename) then
-      exit(true);
+    i:=FileExistsILogged(Filename);
+    if i=1 then exit(true);
+    if i>1 then
+      Cache.RaiseDuplicateFile(Filename);
   end;
   Result:=false;
 end;
@@ -1380,6 +1438,7 @@ begin
   Log.RegisterMsg(mtInfo,nUnitSearch,sUnitSearch);
   Log.RegisterMsg(mtInfo,nSearchingFileFound,sSearchingFileFound);
   Log.RegisterMsg(mtInfo,nSearchingFileNotFound,sSearchingFileNotFound);
+  Log.RegisterMsg(mtFatal,nDuplicateFileFound,sDuplicateFileFound);
 end;
 
 function TPas2jsFilesCache.GetAllJSIntoMainJS: Boolean;
@@ -1605,6 +1664,12 @@ end;
 
 procedure TPas2jsFilesCache.FindMatchingFiles(Mask: string; MaxCount: integer;
   Files: TStrings);
+
+  procedure TooMany(id: int64);
+  begin
+    raise EListError.Create('found too many files "'+Mask+'". Max='+IntToStr(MaxCount)+' ['+IntToStr(id)+']');
+  end;
+
 var
   p, StartP, i: Integer;
   Filename, CurMask: String;
@@ -1629,7 +1694,7 @@ begin
         begin
           // e.g. /path/unit*.pas
           if Files.Count>=MaxCount then
-            raise EListError.Create('found too many files "'+Mask+'"');
+            TooMany(20180126091916);
           Files.Add(Filename);
         end else begin
           // e.g. /path/sub*path/...
@@ -1643,7 +1708,7 @@ begin
   if DirectoryCache.FileExists(Mask) then
   begin
     if Files.Count>=MaxCount then
-      raise EListError.Create('found too many files "'+Mask+'"');
+      TooMany(20180126091913);
     Files.Add(Mask);
   end;
 end;
@@ -1830,7 +1895,7 @@ begin
   end;
 end;
 
-function TPas2jsFilesCache.IndexOfInsertFilename(const aFilename: string
+function TPas2jsFilesCache.IndexOfInsertJSFilename(const aFilename: string
   ): integer;
 var
   i: Integer;
@@ -1841,17 +1906,17 @@ begin
   Result:=-1;
 end;
 
-procedure TPas2jsFilesCache.AddInsertFilename(const aFilename: string);
+procedure TPas2jsFilesCache.AddInsertJSFilename(const aFilename: string);
 begin
-  if IndexOfInsertFilename(aFilename)<0 then
+  if IndexOfInsertJSFilename(aFilename)<0 then
     InsertFilenames.Add(aFilename);
 end;
 
-procedure TPas2jsFilesCache.RemoveInsertFilename(const aFilename: string);
+procedure TPas2jsFilesCache.RemoveInsertJSFilename(const aFilename: string);
 var
   i: Integer;
 begin
-  i:=IndexOfInsertFilename(aFilename);
+  i:=IndexOfInsertJSFilename(aFilename);
   if i>=0 then
     InsertFilenames.Delete(i);
 end;
@@ -1862,5 +1927,34 @@ begin
   DirectoryCache.GetDirectory(aDirectory,true,false).GetFiles(Files,FullPaths);
 end;
 
+procedure TPas2jsFilesCache.RaiseDuplicateFile(aFilename: string);
+
+  procedure E(const File1, File2: string);
+  begin
+    raise EPas2jsFileCache.Create(SafeFormat(sDuplicateFileFound,[File1,File2]));
+  end;
+
+var
+  Dir: TPas2jsCachedDirectory;
+  i: Integer;
+  List: TStringList;
+  ShortFilename: String;
+begin
+  Dir:=DirectoryCache.GetDirectory(ExtractFilePath(aFilename),true,false);
+  ShortFilename:=ExtractFilename(aFilename);
+  i:=Dir.IndexOfFileCaseSensitive(ShortFilename);
+  if i<0 then
+    E(aFilename,'?');
+  List:=TStringList.Create;
+  try
+    Dir.GetSameNamesCaseInsensitive(i,List);
+    if List.Count<2 then
+      E(aFilename,'?');
+    E(Dir.Path+List[0],List[1]);
+  finally
+    List.Free;
+  end;
+end;
+
 end.