Unfortunately I have inherited a piece of unlucky design based on a {$IFDEF} "hell".
What I have roughly looks like this (where MyDbSystemB is what I want to add)
unit MyTable;
interface
uses
// ...
{$IFDEF MyDbSystemA}
DbSystemA ,
{$ENDIF}
{$IFDEF MyDbSystemB}
DbSystemB ,
{$ENDIF}
type
TMyTable = class(
{$IFDEF MyDbSystemA}
TSystemATable
{$ENDIF}
{$IFDEF MyDbSystemB}
TSystemBTable
{$ENDIF}
)
// A public interface implementation
end;
implementation
// ...
end.
A number of units reference TMyTable, but rely on specific functions provided with TSystemATable:
unit oldUnit;
interface
uses MyDbTable;
type
TXy = class(TXyz)
public
procedure Foo();
end;
implementation
procedure TXy.Foo();
var
table : TMyTable;
begin
table := TMyTable.Create();
table.SomeSystemASpecificFunction;
end;
I'd like to find all of these references within a single reference/syntax check. But as I read here that's apparently not really possible
Find all compilation errors in a Delphi project.
What would be the best strategy to go for finding these files to estimate the efforts of porting?
A plain file grep over all *.pas files (there may be a lot of either dead code, or just poorly decoupled stuff)?
I'm also able to provide a surrogate implementation of
TMyTable = class( { ... like above } )
{$IFDEF MyDbSystemB}
public
procedure SomeSystemASpecificFunction; deprecated;
{$ENDIF}
end;
with the implementation of TMyTable, but I'd need to estimate the refactoring cost to do that properly anyways.
Regarding that I also could add a deprecated attribute along with the SomeSystemASpecificFunction surrogate, that will at least give me warnings.
If you know the names of the members of TMyTableA that code takes a dependency on then use Find in Files... (or your favorite alternative grep-like tool) to identify references to those members in the files in your project.
This is likely to be more reliable than any compilation based check anyway.
Any tool which claims to find "all compilation errors in a project" is more often than not lying to you since there is no reliable way to discriminate between errors that have not arisen as a result of some other error earlier in the compilation.
e.g. in a C# solution it is quite common for a simple change to result in dozens if not hundreds of compilation errors which are fixed by resolving only the first error.
i.e. the compiler reports (e.g.) 224 errors when in fact there is only 1 error with 223 errors as a side-effect.
For the same reason, you cannot be sure that the list of errors contains all of the genuine errors you might eventually uncover. In some cases the compiler might yet be defeated to the point of not even attempting to compile some code that contains the errors you are looking for, as a consequence of those side-effect errors.
Certainly, in the list of dozens or hundreds of errors you might then be able to grep to find ones that appear to be candidates for the "genuine" errors you are looking for (i.e. that reference the specific members you know to be involved in your change). But all that does is change the data set you are searching for to locate those references. i.e. the compilation error list rather than your project sources.
I've got a really bizarre issue occurring in the Delphi XE2 IDE.
In one package, I have the following classes declared:
TCommandInfo = class
private
fParameters : TCommandParameters;
// other fields...
public
property Parameters : TCommandParameters read fParameters;
// other properties...
end;
TReceiveCommand = class(TCommand)
// other fields and properties
private
fInfo : TCommandInfo;
public
property Info : TCommandInfo read fInfo;
end;
TReceiveErrorCommand = class(TReceiveCommand);
TReceiveDataCommand = class(TReceiveCommand)
// procedures and properties defined, etc.
end;
Now in a completely different package which depends on the package above, I have this member function:
procedure DoDataCommand;
var
cmd : TReceiveDataCommand;
success : Boolean;
params : TCommandParameters;
begin
cmd := TReceiveDataCommand.Create;
success := cmd.Initialize;
if success then begin
// #### ERROR HERE ####
params := cmd.Info.Parameters;
end;
end;
What I'm seeing is that when trying to compile the dependent package, I get an E2003 error saying "Undeclared identifier: 'Info'" and when I CTRL+CLICK on the TReceiveDataCommand to take me to the declaration, the IDE jumps to a different location in the containing packages source file.
I have this very same code running on my machine at work and this works without fail. I'm wondering if there are some lingering BPL's lurcking around somewhere however I've had a good clear out.
It seems odd that the IDE takes me to the wrong location when trying to jump to the TReceiveDataCommand class source.
Any suggestions please?
The TReceiveCommand type is defined in a different package. The compiler uses the .dcp file to resolves names in that different package. If Info is not recognised then clearly the .dcp file that the compiler is finding does not match the source code in the question.
The logical conclusion is that the compiler is finding an out of date .dcp file.
I have had this happen only when I migrated from Xe6 to xe7. It was linking in both the xe6 stuff and xe7. As the project conversion/migration had not done its job. I would check the paths in the dproj files.
And now for a completely obvious question - have you rebuilt ?
An example with types with the same identity (TLevel and integer)
unit UnitType;
interface
type
TLevel = integer;
TObj = class
public
procedure Test(Level: TLevel);virtual;
end;
There's another unit where another object inherits from this object (Notice integer instead of TLevel, but this is not a problem since they're not distinct)
unit UnitOther;
interface uses UnitType;
type
TInhObj = class(TObj)
public
procedure Test(Level: integer);override;
end;
Everything compiles as usual.
Now I modify TLevel type to be distinct
TLevel = type integer;
and try to compile, but everything compiles fine.
I go to UnitOther and change something unrelated (even just resave it). Now I have "declaration of Test differs from previous declaration" in unit UnitOther
Is this correct actions or a bug that was fixed in latest versions of Delphi? (mine is 5)
I'm using Delphi XE and it still behaves exactly as you described. One workaround is to periodically run the Build event (i.e. before you commit your code). This isn't a very eloquent solution but at least it will allow the changed typed to be detected without having to touch all the files that use it.
In Delphi 7 whenever I control+clicked a function/procedure it took me to that function/procedure. But it is not working in Delphi XE - at least not with all functions. I have a function called Associate in ExtUtils.pas
The function is correctly compiled so the compiler can find the ExtUtils.pas (and of course the ExtUtils is added to the Uses clause and its folder its added in 'Library path'). But when I control+click the function or the unit name, it doesn't take me there.
Any way to fix this?
UPDATE1:
Also, Control+Click on a function (declare in the current unit) does not move the cursor in the INTERFACE section where the function is declared.
UPDATE2:
I temporary put the ExtUtils unit in project's folder and now it works. So, the Control+Click by itself it works but it seems that the IDE has problems finding the unit even it its folder is present in Library Path and Browsing Path.
Similar reports:
http://webcache.googleusercontent.com
http://webcache.googleusercontent.com
http://cc.embarcadero.com/Item/28269
One report right here (see answers below)
New test:
I have fully uninstalled Delphi (and manually delete the files and registry leftovers). Then reinstalled again. NO additional tools except CodeSite were installed, not even the databases. Then I created a new project. It contains a button. When I click the button, it runs the TestMe procedure which is defined in an external PAS file called TestUnit.Pas. I added the path to this library in Library Path and Browsing Path. But the Control+Click on TestMe procedure is still not working! If I hover the mouse over the TestMe procedure, the pop-up says "Declared in TestUnit", where the 'TestUnit' word is a blue link. If I click it I hear a Windows system sound but the IDE doesn't take me there (to the unit).
The TestMe procedure is this:
procedure TestMe;
begin
Beep(800, 500);
end;
If I control+click the Beep procedure, it takes me to Windows.pas. So, this is working.
Please let me know if you have in mind a different test.
UPDATE:
And now it works! Without any apparent reasons! I just open and closed and compiled the project. But I make no changes to Delphi except these two: AutoSave options-> Editor files and Project Options.
UPDATE:
This cannot be!!!
So, now I can access the TestUnit.pas file when I control+click on TestMe procedure.
So, I moved the original PAS file (ExtUtils.pas) that didn't wanted to work in my initial test (before Delphi reinstall) in the same folder where TestUnit.pas is. Guess what: I can open (with control+click) to TestUnit.pas but not the ExtUtils.pas!!!!
Delphi acts so strange and inconsistent!
UPDATE:
I edited ExtUtils.pas and now I cannot open AGAIN TestUnit.pas.
Ken White won't let me say that Delphi could possible have bugs. So I cannot use the 'bug' together with 'Delphi'. Can anybody put these words together for me?
UPDATE:
I totally removed any reference to ExtUtils.pas - so I restored the project to the point where it worked (with TestUnit). But now the bug persists. Even if few seconds before it worked with TestUnit now its not working again.
UPDATE:
Now I realize an important thing: in my source code (in the test project) I have a single line of compilable code:
procedure TForm1.Button1Click(Sender: TObject);
begin
TestMe;
end;
The blue dots does not appear for this code - as it wouldn't have been compiled. In those few minutes when the program worked, I have seen the blue dots.
I have also excluded 'AutoSave options-> Editor files and Project Options' as a possible cause for this issue.
UPDATE:
I have found a way to fix the problem... for few minutes: I move the project and the library in a different folder (any location will do it). The control+click will work for a while. It even works if I put the files back into the original folder. So, it seems that Delphi keeps some kind of cache of some files. As long as the cache is broken and it keeps the cache, control+click won;t work. But when I move the files, it has to recreate that cache so it will work until the issue reappears and it is stored in the cache.
Here we are 5 developers using Delphi 2010 and 2 also using XE and we are experiencing the same thing with the Ctrl-click as you. It seems to stop working randomly. We never could find a pattern or a fix for that. So from time to time we hear swearing coming from cubicles...
When that happens, I use shift-ctrl-F, to do a search.
Sylvain
First, thanks for you all to give hints about this problem. Maybe this is a question long time ago, but at last, after tried many many times, I think the problem cause is, actually, in the "project source code"
IDE version: Delphi XE
please try:
in the Project Options >> Delphi Compiler>>Compiling , ensure:
Debug Information: true
Symbol Reference Info: Reference info
in the Project Source file(dpk file, open by Project >> View Source),
remove {$REFERENCEINFO OFF}
or change to {$REFERENCEINFO ON}
Note that step 2 is very important, even step 1 done, it still can not browse source without step 2.
I'm using Delphi 5 and the Ctrl-click have also problems, i don't know if it still working in the new delphi IDEs but i can go from declaration to implementation using CTRL-SHIFT-UpArrow or DownArrow.
Hope it helps.
There have always been these two distinct options in Delphi:
Library path – used when compiling your app.
Browsing path – used by Code Insight, i.e. when control-clicking identifiers too.
You need to check the second one. It must include the path(s) to the source files you are trying to navigate with Ctrl+Click.
I've found that if I use a record type in the interface section and it's not defined by a type expression, Ctrl-Click and other jumping functions (Ctrl+Shift+Up/Down) won't work.
type
TForm1 = class(TForm)
...
public
Something:record
A, B:integer;
end;
procedure DoSomething;
end;
With the code above I can't jump to implementation of the procedure with Ctrl+Shift+Down. The fix I have to use:
type
TMyRecord = record
A, B:integer;
end;
TForm1 = class(TForm)
...
public
Something:TMyRecord;
procedure DoSomething;
end;
Tested with Delphi XE4.
For future reference. Using Delphi 2010 i have found that a ; preceding virtual in the interface section makes a difference;
function MyProc(): String; overload; virtual;
function MyProc(): Integer; overload; virtual;
// >> ^ <<
This ; character can break the CTRL+Click (code insight) functionality. Compiles fine nonetheless.
I had just made a new groupproject with two projects in Delphi 11. After that I was having problem using Ctrl + Click to jump to functions. I right clicked the groupproject and did "Clean All" and then "Build All" after that it was working for me again.
(Symbol Reference info)This option has no effect unless Debug information and Local symbols (see above) are enabled.
Code completion and code navigation features (Ctrl+Click) work only when Symbol Reference info is set to Reference info.
Solved!
It works for me, change the Code Insight type.
This happens to me quite often, specially when two IDE is opened at the same time.
The way I have found to fix this is:
Clean your project.
List item
Close the IDE.
With the Windows Explorer, navigate to your project.
Search for *.dcu Delete all the .dcu
Launch the IDE and load your project.
Compile it.
At this point, the code navigation (Ctrl+Click) should work.
I have just started working with RemObjects Pascal Script. and have been trying to follow the remobjects tutorial.
http://devcenter.remobjects.com/articles/?id={2FFC1EE9-F18D-4B11-9DE4-1BA0A79D0D04}
all was going fine up to the part you run
begin
ShowNewMessage('Show This !');
end.
where it claimed it does not know of it.
but i have it here
procedure Tmainwindow.ceCompile(Sender: TPSScript);
begin
Sender.AddMethod(Self, #Tmainwindow.ShowNewMessage,
'procedure ShowNewMessage(const Message: string);');
end;
procedure ShowNewMessage(const Message: string);
procedure Tmainwindow.ShowNewMessage(const Message: string);
begin
//ShowMessage('ShowNewMessage invoked:'#13#10+Message);
end;
added on the compile event as instructed... it all compiles in delphi but when i run the code from within my executable it says it dont exist.
secondly if i add any plugins to improve the function calls of the script i get this..
please help i realise i may be doing something silly here im new to rem objects.
Well, I tried building the example as shown on that page, and it compiled and ran correctly for me. Try using the example shown at the top of the page, under "The following code will compile and...". Just make sure to leave out the line that replaces the script text.
As for the plugins, it can't register your event types because they refer to object classes that haven't been registered yet. Unfortunately, the PS Plugin system doesn't have any way of automatically resolving dependencies, and the compiler's error message doesn't tell you which type it couldn't find. You'll need the debugger to help you resolve this. But a lot of the basics, including TObject (yes, you have to import it explicitly) are found in TPSImport_Classes.
i have the same Problem. That has nothing to do with the syntax, only with the inclusion of the Forms-Unit template for the script compiler.
Sry, i do not have a solution for that problem, because it even occurs when removing the OnMenuDrawItem and OnMenuAdvancedDrawItem events (which both make Problems).
I use BDS 2006, that might be the problem as it uses advanced Forms source code in comparison to what D7 used (which was the version RO PS was actually made for).
So, remove the Forms unit plugin for the compiler, which also includes the menus unit and try it again, that should "solve" your problem.