I am thinking of using metadata in Clojure source code as a way for Eastwood users [1] to disable/enable classes of lint warnings for pieces of Clojure code smaller than a whole top level form.
I want to find out if there are any issues with this approach that I haven't considered yet, either with Clojure as it is now, or with planned future features, e.g. conditional reader/feature expressions [2].
The primary method I've seen used with other lint tools are comments with specially-defined syntax in them that the lint tool recognizes, but are unlikely to be typed by someone who is not using that tool. [3]
I could use that approach. However, we do have metadata available for annotating code, and I'd like to use it for this purpose if there are no significant disadvantages.
Example:
(defn my-fn [a b c]
(let [x (+ a b)]
^{:lint {:disable-linters [ :def-in-def ]}}
(def bar (* x c))
(- b c)))
The kind of metadata that Eastwood would pay attention to for this purpose could be restricted to values on a single key, like :lint in the example above. The extent of the disabling effect would be limited to the form (def bar (* x c)), and only for the type of warning Eastwood calls :def-in-def. Such a warning anywhere outside of that form would still be reported. Warnings other than the :def-in-def kind would still be reported inside of that form.
The issues I have thought of so far:
Metadata cannot be applied to any literals except symbols. That doesn't seem like a big hindrance to me -- one could apply the metadata to the next larger enclosing form/vector/map/set. There may be nasty examples where the disabling extent would be increased more than one would want, but I haven't thought of one yet.
Eastwood would need to 'claim' at least one key value to affect its behavior, and if I'm not careful that could collide with another tool's use of such a key. I could use :eastwood/lint to make that very unlikely, but would prefer something a bit shorter.
Any others?
Thanks,
Andy
P.S.: Some other questions you may be thinking of:
This doesn't affect Clojure itself, so why are you asking? No, it doesn't affect how Clojure is implemented. I'm not asking because I want to change how Clojure works for this. I am asking because I want to choose a method that doesn't have already-known problems with it.
Why disable warnings selectively? Because then you can disable warnings that have been manually verified to be not-really-a-bug, and the next run of the lint tool will produce no warnings. You can interpret the lack of warnings to mean that the only warnings found were in the few suppressed places, and nowhere else.
Why disable warnings in a section of code smaller than a function? Because if you introduce a bug that linting can catch outside of those small sections, but inside the same function, it will be reported the next time you lint.
Why not write a lint tool that never produces warnings for correct code? That is computationally undecidable, if it is even well defined. Disregarding that, it can be difficult to write linters that avoid false positives without also resulting in more false negatives (i.e. there was a bug, but lint was silent about it).
[1]
https://github.com/jonase/eastwood/[2]
http://dev.clojure.org/display/design/Release.Next+Planning
[3] Here are some examples for a C lint tool called splint:
http://www.splint.org/manual/html/appC.html