How to find unused imports in umbrella header architecture? - swift

I am looking to find unused imports in an umbrella architecture. The imports are used within swift files. These files receive their imports from Objective-C headers so a text based search would not work. I wrote a script that searches for imports and checks if they are used within the class through text. But the issue is that some imports do not have to be explicitly stated. For example, if we have a framework foo that we use by:
import foo
and that framework has
#import <Example/Example.h>
in its own umbrella header foo.h. I have access to Example, without explicitly importing it.
So the issue is that we cannot see if an import is unused because it does not have to be explicitly imported. Is there a way we can detect unused imports?
I created a text based script in python that searches through a code base and checks for imports that are not used. It would go through directories and look for specific imports, and if they are present check if they are actually being used within the class. I expected that this would work without considering the umbrella architecture. But because there are scenarios where imports do not have to be explicitly stated, this did not work.

Related

Why does Erlang offer both `import` for modules and `include` for headers?

Erlang's -import() directive lets you import code from other modules. Its include() directive lets you import code from headers. Why reasons are there to prefer either one over the other?
My hunch is that headers are good for short, easy-on-the-compiler kinds of code, such as record definitions, when you don't want to have to qualify the
Learn You Some Erlang states[1] that "Erlang header files are pretty similar to their C counter-part: they're nothing but a snippet of code that gets added to the module as if it were written there in the first place." Thus inclusion seems to cause the compiler to duplicate effort across different modules. And header files are what appear to be an optional complication on top of the mandatory module system. So why would I ever use a header file?
[1] https://learnyousomeerlang.com/a-short-visit-to-common-data-structures
Erlang's -import just allows you to call imported functions without the Module. It hurts legibility and should not be used: You need to check the import directive to know whether a function is local or external to the module.
With header files you get the same functionality as in C, you can use them to share -record definitions instead of having a dto-like module (1), you can use them to include -defines to use the same macros (2).
1:
-record(position, {x, y}).
Imagine that you have #position{} throughout the code, instead of defining the record everywhere and updating all of the copies when the record definition changes, you use a header (or a dto module with opaque types, but that's for another question).
And let's just hope that you remember to update all the copies, otherwise chaos ensues.
2:
-define(ENUM01, enum01).
-define(DEFAULT_TIMEOUT, 1000).
Instead of using enum01 and 1000 everywhere, which is error prone and requires multiple updates if you need to change them, you define them in a header and use them as ?ENUM01 and ?DEFAULT_TIMEOUT
Or you can be more thorough when testing:
-ifdef(TEST).
-define(assert(A), true = A).
-else
-define(assert(A), A).
-endif.
Or you can include some useful information:
-define(LOG(Level, X), logger:log(Level, X, #{line => ?LINE}).
The Erlang standard library uses header files to provide the ability to add metadata to your code.
For instance, EUnit functionality:
-include_lib("eunit/include/eunit.hrl").
import is helpful in building encapsulations, whereas include is kind of pre-processing(which means code will be part of the unit before it gets through the compiler).
An import ensues a dependency between two modules, which means a module A importing module B has B as dependency ... Whereas an include is extensional which means a module has included some code and that code is part of the module itself, and that is what header files do.
module(s) and header(s) are 2 semantically different things and serve different purposes. With modules, we can build abstractions by using the export(s), keep things confined by not exporting them, import from other modules(but they are not exported by default), re-export imported things etc etc. So when we import stuff, we can call upon functions from the other module, but only those which are exported in the other module. However that is not the case with header files. Everything inside a header file becomes part of the module which includes them. There is no sense of export/import inside header files. And header files are quite useful for writing and distributing definition(s) which otherwise could lead to redundancy in case of large programs.
So essentially they are 2 different things, so 2 different keywords available at our disposal. So don't prefer one over the other. Learn both of them as we need both of them.

Flutter imports: relative path or package?

In Flutter, for importing libraries within our own package's lib directory, should we use relative imports
import 'foo.dart'
or package import?
import 'package:my_app/lib/src/foo.dart'
Dart guidelines advocate to use relative imports :
PREFER relative paths when importing libraries within your own package’s lib directory.
whereas Provider package says to always use packages imports :
Always use package imports. Ex: import 'package:my_app/my_code.dart';
Is there a difference other than conciseness? Why would packages imports would reduce errors over relative imports?
From the same Dart guidelines, further down they give this reason for the relative imports:
There is no profound reason to prefer the former—it’s just shorter, and we want to be consistent.
Personally, I prefer the absolute method, despite it being more verbose, as it means when I'm importing from different dart files (in other folders), I don't have to work out where the file to be imported is, relative to the current file. Made-up example:
I have two dart files, at different folder levels, that need to import themes/style.dart:
One is widgets/animation/box_anim.dart, where the relative path import would be:
import '../../themes/style.dart';
The other is screens/home_screen.dart with the relative import:
import '../themes/style.dart';
This can get confusing, so I find it better to just use the absolute in both files, keeping it consistent:
import 'package:myapp/themes/style.dart';
And just stick that rule throughout. So, basically, whatever method you use - Consistency is key!
The Linter for Dart package, also has something to say about this, but is more about the Don'ts of mixing in the '/lib' folder:
DO avoid relative imports for files in lib/.
When mixing relative and absolute imports it's possible to create
confusion where the same member gets imported in two different ways.
An easy way to avoid that is to ensure you have no relative imports
that include lib/ in their paths.
TLDR; Choose the one you prefer, note that prefer_relative_imports is recommended in official Effective Dart guide
First of all, as mentioned in this answer, Provider do not recommands package imports anymore.
Dart linter provides a list of rules, including some predefined rulesets :
pedantic for rules enforced internally at Google
lints or even flutter_lints (previously effective_dart) for rules corresponding to the Effective Dart style guide
flutter for rules used in flutter analyze
Imports rules
There is actually more than two opposites rules concerning imports :
avoid_relative_lib_imports, enabled in pedantic and lints rulesets, basically recommend to avoid imports that have 'lib' in their paths.
The two following are the one you mention :
prefer_relative_imports, enabled in no predefined rulesets, but recommended in Effective Dart guide in opposition to :
always_use_package_imports, enabled in no predefined rulesets. Which means that it is up to you and to your preferences to enable it (be careful, it is incompatible with the previous rule)
Which one should I choose?
Choose the rule you want ! It will not cause any performance issue, and no rule would reduce errors over the other. Just pick one and make your imports consistent across all your project, thanks to Dart linter.
I personnaly prefer using prefer_relative_imports, as it is recommended by Dart team, with this VSCode extension which automatically fix and sort my imports.
Provider do not need packages imports anymore.
This was a workaround to an old Dart bug: Flutter: Retrieving top-level state from child returns null
TL;DR, by mixing relative and absolute imports, sometimes Dart created a duplicate of the class definition.
This led to the absurd line that is:
import 'package:myApp/test.dart' as absolute;
import './test.dart' as relative;
void main() {
print(relative.Test().runtimeType == absolute.Test().runtimeType); // false
}
Since provider relies on runtimeType to resolve objects, then this bug made provider unable to obtain an object in some situations.
My 5 cents on the topic are that absolute (package:my_app/etc/etc2...) imports cause much less trouble than relative ones (../../etc/etc2...) when you decide to reorganize/cleanup your project`s structure because whenever you move a file from one directory to another you change the "starting point" of every relative import that this file uses thus breaking all the relative imports inside the moved file...
I'd personally always prefer absolute to relative paths for this reason
This question already has good answers, but I wanted to mention an insanely annoying and hard-to-find problem I experienced with unit testing that was caused by a relative import.
The expect fail indicator for an exception-catching expect block
expect(
() => myFunction,
throwsA(isA<InvalidUserDataException>())
);
was showing the actual result as exactly the same as the expected result, and zero indication of why it's failing.
After massive trial-and-error, the issue was because the expected InvalidUserDataException (a custom-made class) was being imported to the test file in RELATIVE format vs PACKAGE format.
To find this, I had to compare side-by-side, line-by-line, call-by-call between this test file and another test file that uses the exact same exception expecters (It's lucky, we had this), and just by chance, I happened to scroll to the top of this file's imports and see the blue underline saying prefer relative imports to /lib directory.
No, they're not preferred; they're necessary, because the moment I changed that to a PACKAGE (absolute) import, everything suddenly started working.
What I learned from this is: Use absolute imports for test files (files outside the lib directory)
e.g. inside of src/test/main_test.dart
DON'T: use import '../lib/main.dart'
DO: use package:my_flutter_app/main.dart
Maybe other people knew this already, but I didn't, and I couldn't find anything online with searches about this issue, so I thought I would share my experience that might help others who got stuck around this.
Does anyone know why this happens?
Edit: For context, this happened while using Flutter 2.1.4 (stable) with Sound Null Safety
Do you use Integration Tests?
If the answer is yes, then in most cases you need to use package imports. When you attempt to run your integration tests on a physical device, any relative imports will not be able to find what they're looking for.
Example: https://github.com/fluttercommunity/get_it/issues/76
You can enforce package imports in your project by using these two linting rules:
always_use_package_imports
avoid_relative_lib_imports
I also prefer package imports because they stick even when rearranging your files and folders. Relative imports frequently break and it's a pain to have to remove them and reimport the offending dependency.
One very simple reason to not use package imports: rename your package without editing every dart file
Renaming can happen a few times while the product does not have a definitive name, and you or your product owner decides to change it.
It is much more painful to rename with package imports as your package name is in every import.
Of course you can change it with a find/replace query, but it's a useless edit on every dart file you can avoid with relative imports.
Plus, vscode allows to automatically update relative imports on file move/rename and I have never had any issue with this feature.

Package name lookup rules in scala

I came out to scala programmin from Java so it's not clear to me how we should use relative imports in Scala and what is the exact name lookup rules? Suppose I have the following:
pack.age
|
|----MyClass.scala
com.age
|
|---AnotherClass.scala
I need to import MyClass.scala into AnotherClass.scala. Since Scala supports only relative imports I wrote the following:
import _root_.pack.age.MyClass
and it worked fine. But when I tried to delete _root_ from there, there was no compile time error either.
import pack.age.MyClass
works fine as well.
So, what is the package name lookup rules in Scala?
I believe there is an order of operations here. If you had package.age.MyClass within com.age (ie. com.age.package.age.MyClass), as well as package.age.MyClass, the former would be picked up. If you wanted the latter, you would need to use the root syntax.
As there is only one place this class can be picked up from (in root), that is the package picked up.
All imports are relative, so sometimes collisions can appear. For example, if you have package com.org.project.scala then next import scala._ looks up for system package too. _root_ is implicit top package that can be utilised for simulation of absolute path.

Does having multiple `package` declarations slow the compiler down?

I know that splitting a package declaration across multiple lines creates an implicit import. So this:
package com.me.project
package module
Is equal to:
package com.me.project.module
import com.me.project._
However, if an object in the project package changed, would it trigger sbt to recompile the current file, or would that depend on whether the changed object was actually invoked within the current scope? Basically, I'm wondering whether being more explicit, E.g:
package com.me.project.module
import com.me.project.UtilClass
import com.me.project.Rng
would help speed up compile times vs either of the first two approaches?
No, it wouldn't help to speed up anything. Actually, it could mean that your compilation times even increase because doing single imports mean that the compiler have to parse more lines of code. But because that would still only take nanoseconds it doesn't really count.
An import declaration is nothing more than an information to the compiler about where to look up declarations. A compiler doesn't need to do anything with that information unless you reference it from within your code. In this case the compiler has to compile that file too, in order to being able to find out if your code would typecheck or not.
In other words, if you actually use two declarations from a set of hundreds, they are the only ones that would trigger a recompilation of your source code when they change.
I don't say that this is the only possible behavior, because it could be implemented in any way, but implementing a compiler in a way that it triggers a recompilation of your code when the code that corresponds to an import declaration changes doesn't make a lot of sense, when you think about it, that is why it is very sure to say that it will not do it. Because, what would happen? Every source files probably contains a package declaration and some imports. If your code gets recompiled because one of a declaration in the range of a wildcard imports changes, then this needs to happen for all other files as well. And because you can be sure that in every application all the existing imports span more or less the entire classpath, the entire classpath needs to be recompiled just because one file changed, which is not the desired behavior.

Less - compile only current file excluding imports

We have a third party less file in our project - say foo.less. foo.less will be compiled to foo.css.
foo.less
foo.css
-- team1.less
-- team1.css
-- team2.less
-- team2.css
team1.less and team2.less both import foo.less.
Team1 has a reference to foo.css and team1.css
on their web pages while
Team2 has a reference to foo.css and team2.css.
How can I get team1.css and team2.css to exclude foo.css in their respective compiled output? What is occurring right now is team1.css and team2.css both have foo.css in them (repetition of css code).
Edit:
team1.less and team2.less imports foo.less to take advantage of a lot of variables and mixins.
Now Available in LESS 1.5
You can import foo.less as a reference, like so:
#import (reference) "foo.less";
The code will be available for referencing variables, mixins, etc., but will not compile to css output.
My question to you is, why are you importing foo.less if you do not want it to be included? If it's because you are using variables or mixins from foo.less, than you could separate those out into a separate less file, and import that instead. That way there would not be any duplicate css. This is good practice in general, that way you can reuse any variables/mixins without importing a bunch of css.