How do I turn specific Delphi warnings and hints off? - delphi

In CodeGear Delphi 2007, how can I turn specific warnings and hints off? I am attempting to turn off H2077 - Value assigned to 'varname' never used.

You are not able to disable specific hints like you can with warnings. Hints are those things that would not have any potential adverse affects on your runtime code. For instance, when you see the hint "Value assigned to 'varname' never used" it is merely a suggestion for something you should probably "clean up" in your code, but it won't cause any potential runtime errors (other than your own logic errors, of course :-). Hints are always best addressed by tweaking the code.
Warnings, on the other hand, are those things that could possibly cause unintended runtime behaviors and really should be addressed. For instance, using a variable before assigning a value to it is clearly a case of an uninitialized variable and that can lead to "bad things." In the vast majority of times, warnings should be addressed by "fixing" the code. Even then, in certain circumstances you may deem the warning as a "false positive" and are certain the code is functioning correctly. In those cases, you can disable a specific warning. Disabling all warnings is dangerous.

Hints? No specific.
You'll have to disable them all:
{$HINTS OFF}
Warnings?
{$WARN _name_of_warning_ OFF|ON|ERROR}
Check here for a full list

Why don't you instead change the code so the hint goes away? Those hints are usually pretty accurate. And if you really feel that the line of code (I'm guessing some variable initialization or other) is useful to the reader of your code even if it is irrelevant to the compiler, you can replace it with a comment.

What Lars said. Also, you can get the complete list of warnings and their current settings by pressing CTRL-O twice. It'll dump a list at the top of the current unit. You can look through there to find the one you need to change. Just remember to delete the list later, or people looking at the code later on will hate you. ;)

To remove a hint for a line of code that has the:
H2077 Value assigned to '%s' never used
You can wrap it in:
{$HINTS OFF}
//...
{$HINTS ON}
For example, from the buggy Vcl.ComCtrls.pas:
procedure TTrackBarStyleHook.Paint(Canvas: TCanvas);
//....
begin
if not StyleServices.Available then Exit;
{$HINTS OFF}
Thumb := ttbTrackBarDontCare; //value assigned to 'Thumb' never used
{$HINTS ON}
//...
end;
Note: Any code released into public domain. No attribution required.

Related

IfThen(Assigned(Widget), Widget.Description, 'No Widget') doesn't crash. Should it?

In code that I help maintain, I have found multiple examples of code that looks like this:
Description := IfThen(Assigned(Widget), Widget.Description, 'No Widget');
I expected this to crash when Widget was nil, but when I tested it, it worked perfectly.
If I recompile it with "Code inlining control" turned off in Project - Options - Compiler, I do get an Access Violation.
It seems that, because IfThen is marked as inline, the compiler is normally not evaluating Widget.Description if Widget is nil.
Is there any reason that the code should be "fixed", as it doesn't seem to be broken? They don't want the code changed unnecessarily.
Is it likely to bite them?
I have tested it with Delphi XE2 and XE6.
Personally, I hate to rely on a behavior that isn't contractual.
The inline directive is a suggestion to the compiler.
If I understand correctly what I read, your code would also crash if you build using runtime packages.
inlining never occurs across package boundaries
Like Uli Gerhardt commented, it could be considered a bug that it works in the first place. Since the behavior isn't contractual, it can change at any time.
If I was to make any recommendation, I would flag that as a low priority "fix". I'm pretty sure some would argue that if the code works, it doesn't need fixing, there is no bug. At that point, it becomes more of a philosophical question (If a tree falls in a forest and no one is around to hear it, does it make a sound?)
Is there any reason that the code should be "fixed", as it doesn't seem to be broken?
That's really a question that only you can answer. However, to answer it then you need to understand fully the implications of reliance on this behaviour. There are two main issues that I perceive:
Inlining of functions is not guaranteed. The compiler may choose not to inline, and in the case of runtime packages or DLLs, a function in another package cannot be inlined.
Skipping evaluation of an argument only occurs when the compiler is sure that there are no side effects associated with evaluation of the argument. For instance, if the argument involved a function call, the compiler will ensure that it is always evaluated.
To expand on point 2, consider the statement in your question:
Description := IfThen(Assigned(Widget), Widget.Description, 'No Widget');
Now, if Widget.Description is a field, or is a property with a getter that reads a field, then the compiler decides that evaluation has no side effects. This evaluation can safely be skipped.
On the other hand, if Widget.Description is a function, or property with a getter function, then the compiler determines that there may be side effects. And so it ensures that Widget.Description is evaluated exactly once.
So, armed with this knowledge, here are a couple of ways for your code to fail:
You move to runtime packages, or the compiler decides not to inline the function.
You change the Description property getter from a field getter to a function getter.
If it were me, I would not like to rely on this behaviour. But as I said right at the top, ultimately it is your decision.
Finally, the behaviour has been changed from XE7. All arguments to inline functions are evaluated exactly once. This is in keeping with other languages and means that observable behaviour is no longer affected by inlining decisions. I would regard the change in XE7 as a bug fix.
It already has been fixed - in XE7 and confirmed that this was supposed to be wrong behavior.
See https://quality.embarcadero.com/browse/RSP-11531

Is it possible to hint a specific if-statement branch is most likely to be executed in the Delphi compiler?

This is a common question for other compilers (C#, VC++, GCC.) I would like to know the same thing for the Delphi compiler (any version; I'm currently using 2010 and XE2 and will use XE4 soon.)
I have a situation in high-performance code I'm writing where a condition has to be checked, but in most cases no action needs to be taken:
if UnlikelyCondition then
HandleUnlikelyCondition
else
HandleLikelyCondition
end;
Often nothing needs to be done for the likely case:
if UnlikelyCondition then
HandleUnlikelyCondition
else
Exit
end;
I would like to hint to the compiler that the second branch of the if statement is the one to optimize for. How can I do this in Delphi?
Current code
Currently, I have written my code assuming that the if statement's condition equalling true is the best thing to optimise for:
if LikelyCondition then
HandleLikelyCondition
else
HandleUnlikelyCondition
end;
or
if LikelyCondition then Exit;
HandleUnlikelyCondition;
In a test just now using the first of these two examples, I get a 50% extra performance boost restructuring my if statements like this, ie assuming the if statement's condition is true. Perhaps another way of phrasing the question is, is this the best I can do?
If you have not encountered branch misprediction before, this epic answer is an illuminating read.
There is nothing in the language or compiler that allows you to supply hints for branch prediction. And in any case, modern architectures would ignore those hints even if the compiler emitted object code that contained hints.

What this Delphi's define {$WARN GARBAGE ON} means?

I am keen on finding new conditional defines and keywords in the Delphi language which are undocumented.
Stuff like {$WARN GARBAGE ON}
http://qc.embarcadero.com/wc/qcmain.aspx?d=77686
I report such stuff in Quality Central but the issue got closed and "Promoted to Internal Database".
What does this mean? Should I expect an answer to this already year and half old question?
These two warnings are now documented.
GARBAGE: Turns on or off warnings produced when the presence of non-whitespace text is detected past the end of the final 'end.' in the program, unit, library or package
UNIT_EXPERIMENTAL: Turns on or off all warnings about the experimental directive applied to a unit declaration.
Presumably the report was marked as fixed once the documentation was added.

How to filter Delphi 2010 compiler output (hints)?

I'm trying to get rid of some hints(*) the Delphi compiler emits. Browsing through the ToolsAPI I see a IOTAToolsFilter that looks like it might help me accomplish this through it's Notifier, but I'm not sure how to invoke this (through what xxxServices I can access the filter).
Can anyone tell me if I´m on the right track here? Thanks!
(*) In particular, H2365 about overridden methods not matching the case of the parent. Not so nice when you have about 5 million lines of active code with a slightly different code convention than Embarcadero's. We've been working without hints for months now, and we kinda miss 'm. :-)
Even if you could query BorlandIDEServices for IOTAToolsFilter, that interface isn't going to help you do what you're asking. That interface was introduced as part of a mechanism for adding additional build tools (compilers, etc.) to the IDE (before the IDE used MSBuild). It allowed you to write a custom "filter" to handle output from a particular build tool, but it would not let you apply a filter to one of the built-in tools (like the delphi compiler).
The reason the Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) call fails in Delphi2010 is that once MSBuild support was added to the IDE, the old way of adding build tools to the IDE was disabled, and the BorlandIDEServices interface no longer supported IOTAToolsFilter.
The declaration of IOTAToolsFilter should probably have been marked deprecated in ToolsAPI.pas (or least it should have been mentioned in the source code comment that it is no longer supported).
As far as your desire to filter a particular hint, I'm not aware of a way to do that via the ToolsAPI. It seems like a reasonable thing that can be added to IOTAMessageServices (the ability to enumerate, filter, and possibly change the messages in the IDE's Message View). I would enter a request in QualityCentral for that.
Also, please vote for QC #35774 (http://qc.embarcadero.com/wc/qcmain.aspx?d=35774), as if that were implemented, you would not need to use the ToolsAPI for this sort of thing.
According to http://docwiki.embarcadero.com/RADStudio/en/Obtaining_Tools_API_Services it should be possible to access it directly using BorlandIDEServices, eg:
var
OTAToolsFilter: IOTAToolsFilter;
begin
if Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) then
ShowMessage('supports IOTAToolsFilter')
else
ShowMessage('IOTAToolsFilter NOT supported');
end;
However this doesn't return the desired interface in Delphi 2010 (you'll get the not supported message), so there's either an error in the documentation, or an error in BorlandIDEServices not returning the correct interface.

Delphi 5: Ideas for simulating "Obsolete" or "Deprecated" methods?

i want to mark a method as obsolete, but Delphi 5 doesn't have such a feature.
For the sake of an example, here is a made-up method with it's deprecated and new preferred form:
procedure TStormPeaksQuest.BlowHodirsHorn; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;
Note: For this hypothetical example, we assume that using the parameterless version is just plain bad. There are problems with not "using protection" - which have no good solution. Nobody likes having to use protection, but nobody wants to not use protection. So we make the caller decide if they want to use protection or not when blowing Hodir's horn. If we default the parameterless version to continue not using protection:
procedure TStormPeaksQuest.BlowHodirsHorn;
begin
BlowHodirsHorn(False); //No protection. Bad!
end;
then the developer is at risk of all kinds of nasty stuff. If we force the parameterless version to use protection:
procedure TStormPeaksQuest.BlowHodirsHorn;
begin
BlowHodirsHorn(True); //Use protection; crash if there isn't any
end;
then there's a potential for problems if the developer didn't get any protection, or doesn't own any.
Now i could rename the obsolete method:
procedure TStormPeaksQuest.BlowHodirsHorn_Deprecatedd; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;
But that will cause a compile error, and people will bitch at me (and i really don't want to hear their whining). i want them to get a nag, rather than an actual error.
i thought about adding an assertion:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');
...
end;
But i cannot guarantee that the developer won't ship a version without assertions, causing a nasty crash for the customer.
i thought about using only throwing an assertion if the developer is debugging:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
if DebugHook > 0 then
Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');
...
end;
But i really don't want to be causing a crash at all.
i thought of showing a MessageDlg if they're in the debugger (which is a technique i've done in the past):
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
if DebugHook > 0 then
MessageDlg('TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)', mtWarning, [mbOk], 0);
...
end;
but that is still too disruptive. And it has caused problems where the code is stuck at showing a modal dialog, but the dialog box wasn't obviously visible.
i was hoping for some sort of warning message that will sit there nagging them - until they gouge their eyes out and finally change their code.
i thought perhaps if i added an unused variable:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
var
ThisMethodIsObsolete: Boolean;
begin
...
end;
i was hoping this would cause a hint only if someone referenced the code. But Delphi shows a hint even if you don't call actually use the obsolete method.
Can anyone think of anything else?
How about something like
procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
if DebugHook > 0 then asm int 3 end;
// This method is Obsolete! Use XXXXX instead.
Abort; // Optional, makes method useless
// old code here . . .
end;
Kind of a compromise between an assertion and a showmessage. The developer just needs to hit F9 to continue. You could put in an Abort, and then the method would do nothing, and that would force them to switch methods and the break makes them aware of it.
Personally I would recommend upgrading to a newer version of Delphi. 2007 and 2009 are great releases and are really worth the upgrade.
What I've ended up using was a combination of opting into a system where you agree to not have any deprecated code, with output debug strings and breakpoints otherwise.
Like strict html, I've created a Strict define.
All the common units have the obsolete code defined out if Strict is defined. That way the developer has agreed that they will not have deprecated code in their project:
{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; overload; //obsolete
{$ENDIF}
procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean); {$IFNDEF Strict}overload;{$ENDIF}
{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
OutputDebugString(PAnsiChar('TStormPeaksQuest.BlowHaldirsHorn is deprecated. Use BlowHaldirsHorn(Boolean)'));
//Don't debugbreak without a debugger attached!
if DebugHook > 0 then
Windows.DebugBreak;
...
end;
So if the developer wants to have proper code, suffering having to perform code-changes when new things are deprecated, they can:
{$DEFINE Strict}
If not, then there will always be an OutputDebugString, and anyone with Debug View can see (even customers). It's funny to see commercial software (even Microsoft's) with output debug strings left over.
And finally, if there's a debugger attached, then they'll get a debug breakpoint out of nowhere. If anyone asks about, i can take that opportunity to make fun of them.
This doesn't exactly answer your question but it might provide an alternative solution. Could you not update the original function with a default value...
procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean = False);
...so that legacy code compiles and behaves the same but the new functionality is available to new developers.
Why do you want to do this and why don't you want to upgrade the Delphi version?
Without the deprecated tag you really have no clean option to filter the use of deprecated methods. So it depend on where you want to make the concession:
renaming catches the error at compiletime (unless there is another method/function with the same name within scope).
all other methods are only caught at runtime. And this has a risk of slipping into the production code.
What you can do, is create a deprecated log. This won't piss off anybody, and it is no complete disaster if it enters production code. But if your tests have full coverage, you will catch all the culprits. You only have to check the log file after a (test)run.
And of course the best way, is to use grep to find all the occurences of the code and change it.
I'd agree with an optional parameter if it'll do the job. But I can think of situations were optional params won't fit. For instance I have moved functions into new units but kept the olds ones and marked them as deprecated.
I guess whatever solution you go with will also depend on the discipline of your team. Do they actively take notice and work to correct all the hints and warnings for their apps? Hopefully they do but I am shamed to admit that the team I work with (including myself) do not stay on top of all the hints and warnings. Every now and then I fix as many hints & warnings as time permits and we absolutely should fix warnings but in reality we've got to get the job done and are more focused on new features and deadlines.
So my point is, even if you could mark them as deprecated or give a similar hint/warning, do you feel your team will take the time to change their code anyway?
It's not a total solution since you can't differentiate whether they've used the method or not but if it's available in Delphi 5 but you could use the $MESSAGE compiler directive to emit a warning at compile time.
Nothing says "Fix me!" like a compiler break.
That said, I have a colleague who regularly modifies the signatures of 'common code' routines... and yes it is annoying!
My preferred (i.e. our team isn't quite there yet :/) approach is as follows:
All developers must be able to easily perform a full build of all projects on their own machines.
Whoever decides to change common code should bear responsibility for the consequences. I.e. Fix all affected code.
Granted, sometimes said developer might not be ideally suited to properly implementing and verifying all fixes.
But, by the same token the developrs imposed upon to "adopt the new contract" in their own code might not be clear on the subtelties of the new contract. I.e.
Is there anything special that needs to be done in order to use protection?
How is the use of protection implemented?
What are the concerns as to how it could break existing code?
This is a major reason why a comprehensive set of test cases is important.
Generally you want the ripple effect of all the changes applied as soon as possible. I.e. While the finer details of the change are fresh in the originating developer's mind - before attention shifts to something else!
It should be a rare occurance that the ripple effect is so vast (thousands of lines) that you want to apply the change over an extended period of time.
If this is the case, then implement a simple code-metric gathering tool integrated into your build process to report the number of outstanding instances.
I consider point 2 to be of key importance, not least because it emphasises the need for cooperation and communication within the team.
Going back to my opening statement, the sooner you catch and fix an error, the better.
Let the compiler report a break! -- It's the "earliest opportunity" error reporting mechanism we have.
That's my 2 coppers! :D

Resources