[PATCH] D139921: [include-cleaner] Ranking of providers based on hints

Haojian Wu via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 14 05:34:58 PST 2022


hokein added a comment.

I haven't read all code yet, left a few initial comments.



================
Comment at: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h:85
+/// Represents properties of a symbol provider.
+enum class Hint : uint8_t {
+  None = 0x00,
----------------
IIUC, we're using a union bit for symbols and headers: some properties are for both (e.g. Complete); some properties are just for headers (e.g. Public, Canonical).

I found that this model is hard to follow (e.g. for each property, I need to keep thinking about whether this property is for just symbols/headers or both, the hint conversion step from Symbol to Header is not obvious).

What do you think about the following alternative ?

- define two hints (`SymbolHint`, `HeaderHint`)
- an explicit conversion from `SymbolHint` to `HeaderHint`
- `SymbolLocation` class has a `SymbolHint` member (for `Header` as well)






================
Comment at: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h:89
+  /// difference. e.g. types or templated functions/classes.
+  Complete = 0x01,
+  /// Provides a non-private declaration for the symbol. Only absent in the
----------------
nit: since this is a bit union, I'd suggest to use `= 1 << 0`, `= 1 << 1` syntax to define the value.


================
Comment at: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h:90
+  Complete = 0x01,
+  /// Provides a non-private declaration for the symbol. Only absent in the
+  /// cases where file is explicitly marked as such, e.g. non self-contained or
----------------
I think this is no non-private declaration. The `Public` property is for headers, it indicates the symbol is provided by a non-private header.


================
Comment at: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h:93
+  /// IWYU private pragmas.
+  Public = 0x02,
+  /// Declaration is explicitly marked as canonical, e.g. with a IWYU private
----------------
In most cases, this bit is set. If we use a flipped bit (`Private`), we don't need to set it in many places.


================
Comment at: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h:95
+  /// Declaration is explicitly marked as canonical, e.g. with a IWYU private
+  /// pragma that points at this provider.
+  Canonical = 0x04,
----------------
This comment is hard to follow, it doesn't explain the `Canonical`. From the design doc, it means `NameMatch` and `Annotated` headers, I think it would be nice to document them in the comment.

I'd suggest avoid using the `Canonical` name, it remains me too much about the canonical decl in clang. Maybe `Preferred`?


================
Comment at: clang-tools-extra/include-cleaner/lib/FindHeaders.cpp:1
 //===--- FindHeaders.cpp --------------------------------------------------===//
 //
----------------
any reason to change the file property?


================
Comment at: clang-tools-extra/include-cleaner/lib/FindHeaders.cpp:97
       for (const auto *Export : PI->getExporters(FE, SM.getFileManager()))
-        Results.push_back(Header(Export));
+        Results.emplace_back(Export, CurrentHints);
 
----------------
I think `Exporter` is the case we need to handle -- the exporter header should have a higher value (we probably need to add another hint bit).


================
Comment at: clang-tools-extra/include-cleaner/lib/FindHeaders.cpp:100
+      if (auto Verbatim = PI->getPublic(FE); !Verbatim.empty()) {
+        Results.emplace_back(Verbatim, CurrentHints | Hint::Canonical);
         break;
----------------

if FE is `private`, do we want  the `Verbatim` set the public bit? My inclination is yes (the current code behavior is no), it feels counterintuitive that  headers from `getPublic()` is not marked as `Public`.


================
Comment at: clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp:25
 
-std::vector<SymbolLocation> locateDecl(const Decl &D) {
-  std::vector<SymbolLocation> Result;
+Hint hints(const Decl *D) {
+  Hint Hints = Hint::None;
----------------
nit: declHints?


================
Comment at: clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp:161
 
+class HeadersForSymbolTest : public FindHeadersTest {
+protected:
----------------
I think we should have some tests for the hints bit (verify the hint bits are set correctly).


================
Comment at: clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp:266
+  EXPECT_THAT(headersForFoo(),
+              ElementsAre(physicalHeader("test/foo.proto.h"),
+                          physicalHeader("public_complete.h")));
----------------
The result is correct according to the `(canonical, public, complete)` triple order.

But we can come up with a counterexample, e.g. 
 
```
// transitive.h
#include "public_complete.h"

// main.cpp
#include "transitive.h"
Foo foo;
```

We will remove the `transitive.h` and insert the `foo.proto.h`, then we cause a compiling error (incomplete type of `Foo`). Not sure what we should do about it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139921/new/

https://reviews.llvm.org/D139921



More information about the cfe-commits mailing list