[PATCH] D150185: [include-cleaner] Allow multiple strategies for spelling includes.

Haojian Wu via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 1 05:29:16 PDT 2023


hokein added a comment.

thanks, left some comments per our offline discussion.



================
Comment at: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h:104
+/// order is not specified.
+std::function<std::string(llvm::StringRef)> defaultHeaderMapper();
+
----------------
VitaNuo wrote:
> hokein wrote:
> > It is unclear to me why we need `defaultHeaderMapper` and the parameter `MapHeader` in `spellHeader` in the header.
> > 
> > Do we want the caller of `spellHeader` to provide a different HeaderMapper? I don't see a usecase for that -- the current strategy of is to iterate all extension points, if we find the first available one, we just return it; otherwise we use the default fallback (`suggestPathToFileForDiagnostics`). I believe it is enough for `spellHeader` to cover all our cases.
> > 
> > Plugins might need extra information, e.g. clangd-configs for remapping quotes to > angles (or full path re-writes)
> > Reason to push registry to applications and rather take in a functor in >include_cleaner (or just let it be handled by applications completely?)
> 
> This is a quote from our sync notes. I believe the idea was that applications might want to parametrize mapping somehow. When linking via a strategy, you can only provide a class that has a parameterless constructor, though. At least that's my understanding.
Right. 

As discussed, for extra parameters, we can pass the input parameters via a virtual method call. we could pack all parameters into a struct, we could refine the interface like :

```
class IncludeSpeller {
public:
   struct Input {
      const Header& HeaderToInsert;
      HeaderSearch &HS;
      const FileEntry* MainFile;
   };
   
   virtual std::string spell(const Input&) = 0;
};
using IncludeSpellerRegistry = llvm::Registry<IncludeSpeller>;
std::string spellHeader(const IncludeSpeller::Input& Input);
```


Now for each IncludeSpeller, `Input` provides enough information to implement their strategy.
e.g. for our internal one which needs to resolve all symlinks, we can get the FileManager from the `HeaderSearch`.


================
Comment at: clang-tools-extra/include-cleaner/lib/Analysis.cpp:96
+    // Spelling physical headers allows for various plug-in strategies.
+    std::string FinalSpelling = MapHeader(H.physical()->tryGetRealPathName());
+    if (!FinalSpelling.empty())
----------------
as discussed, `tryGetRealPathName` doesn't guarantee it returns an absolute file path, and it is not enough to support our internal use case where we need to resolve the symlink (which requires a `FileManager`). 


================
Comment at: clang-tools-extra/include-cleaner/unittests/IncludeSpellerTest.cpp:1
+//===--- AnalysisTest.cpp -------------------------------------------------===//
+//
----------------
nit: IncludeSpellerTest.cpp


================
Comment at: clang-tools-extra/include-cleaner/unittests/IncludeSpellerTest.cpp:60
+    RootWithSeparator += llvm::sys::path::get_separator();
+    AbsolutePath.consume_front(llvm::StringRef{RootWithSeparator});
+    return AbsolutePath.str();
----------------
we miss to check the return value here -- if it is false (the `AbsolutePath` doesn't start with the `testRoot()`), then we returns an empty string.

The mental model is that each `IncludeSpeller` subclass only implements their strategy for a particular interesting path pattern, if the absolute path doesn't match the pattern, we should return an empty string, claiming that there is no customization for this `IncludeSpeller`. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D150185



More information about the cfe-commits mailing list