This is an archive of the discontinued LLVM Phabricator instance.

Remove a few effectively-unused FileEntry APIs. NFC
ClosedPublic

Authored by sammccall on Apr 6 2022, 2:38 AM.

Details

Summary
  • isValid: FileManager only ever returns valid FileEntries (see next point)
  • construction from outside FileManager (also DirectoryEntry). It's not possible to create a useful FileEntry this way, there are no setters. This was only used in FileEntryTest.
  • operator< (hypothetical callers who want to sort FileEntry*s by UID should probably be explicit about it).

The ugly part here:

  • FileEntryTest was constructing dummy FileEntrys to wrap in FileEntryRef
  • I changed this to use a FileManager as a factory
  • but FileManager hands out *const* FileEntry*s
  • so I needed to change FileEntryRef to wrap *const* FileEntry&

Fortunately this doesn't change the public APIs around FileEntryRef.

Diff Detail

Event Timeline

sammccall created this revision.Apr 6 2022, 2:38 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 6 2022, 2:38 AM
sammccall requested review of this revision.Apr 6 2022, 2:38 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 6 2022, 2:38 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
kadircet accepted this revision.Apr 6 2022, 4:45 AM

thanks lgtm! I would still be looking out for build bot statuses in case there are OS specific code paths that were using isvalid. it might also be worthwhile to send out operator< change in a separate commit, just to give downstream users an opportunity to handle fixes for the two in isolation (or reverts if need be).

clang/lib/Basic/FileManager.cpp
462–463

nit: revert formatting

clang/unittests/Basic/FileEntryTest.cpp
43–44

no need for const_cast here anymore, right?

56

similarly we can drop the const_cast here

This revision is now accepted and ready to land.Apr 6 2022, 4:45 AM
sammccall updated this revision to Diff 420808.Apr 6 2022, 5:10 AM
sammccall marked 2 inline comments as done.

Remove obsolete const_casts

thanks lgtm! I would still be looking out for build bot statuses in case there are OS specific code paths that were using isvalid.

Will do!

it might also be worthwhile to send out operator< change in a separate commit, just to give downstream users an opportunity to handle fixes for the two in isolation (or reverts if need be).

I think it's so unlikely to be used as to not be worth it.

  • It's not possible to put FileEntrys as values in a container, so some code would have to be explicitly comparing them (rather than std::sort or so).
  • Ordering file entries by UID doesn't seem terribly useful - it's neither the cheapest ordering (pointers) nor the most natural.
  • Empirically, there are zero uses in llvm-project and zero in google's downstream repo, which is one of the heavier user of clang APIs. I'd bet there are none anywhere.
clang/lib/Basic/FileManager.cpp
462–463

arc insists on this change here, because it's in the blast radius of the next line and clang-format isn't configured to allow this formatting.

Unless you feel strongly I'd rather not fight the linter when it's not really wrong.
(Happy to reformat the other lines to match though)

kadircet added inline comments.Apr 6 2022, 5:20 AM
clang/lib/Basic/FileManager.cpp
462–463

Unless you feel strongly I'd rather not fight the linter when it's not really wrong.
(Happy to reformat the other lines to match though)

I was suggesting this for preserving history purposes, in theory all of this is old code with intricate semantics so it would be nice to not add more commits to the history chain here. I think it should be possible to just arc diff --nolint (or push without updating the diff in phabricator, which you already probably know, but just in case).

sammccall updated this revision to Diff 420832.Apr 6 2022, 6:56 AM

revert clang-format changes

sammccall marked 2 inline comments as done.Apr 6 2022, 6:57 AM
sammccall added inline comments.
clang/lib/Basic/FileManager.cpp
462–463

Sure, fair enough

The ugly part here:

  • FileEntryTest was constructing dummy FileEntrys to wrap in FileEntryRef
  • I changed this to use a FileManager as a factory

It's not clear *why* you changed this to use a FileManager as a factory. It seems unrelated to removing FileEntry::isValid() (but maybe I'm missing something obvious). It also doesn't seem like an improvement for the test, since FileManager is full of hacks and twisted logic that's hard to reason about, and it's useful to test FileEntry / FileEntryRef / etc. in isolation of that.

Depending on the goal, maybe instead we could abstract out some lower-level API, FileManagerBase or FileEntryFactory or something, which both FileEntryTest and FileManager use.

clang/unittests/Basic/FileEntryTest.cpp
47–52

I don't love this from a layering perspective. FileEntryTest is testing the low-level pieces that are used inside FileManager... using FileManager to generate the FileEntries is awkward.

Maybe it'd be okay if FileManager::getVirtualFile() were trivial, but it's not.

Adding a couple of reviewers that have been looking at FileManager issues with me recently; maybe they have a different perspective.

(also, I neglected to say so explicitly before: removing isValid() SGTM; FileManager clients shouldn't have to worry about it)

dexonsmith added inline comments.Apr 6 2022, 11:22 AM
clang/lib/Basic/FileManager.cpp
462–463

arc insists on this change here, because it's in the blast radius of the next line and clang-format isn't configured to allow this formatting.

Unless you feel strongly I'd rather not fight the linter when it's not really wrong.
(Happy to reformat the other lines to match though)

I know this was already reverted / dealt with (SGTM; I agree with @kadircet, although probably I feel less strongly), but I'm wondering if there's a bug in arc or clang-format to report or fix. Seems to me like this *shouldn't* be considered part of the blast radius. Why should deleting a line trigger reformatting the lines before/after, when those lines are not part of the same construct/statement?

dexonsmith added inline comments.Apr 6 2022, 11:27 AM
clang/include/clang/Basic/FileEntry.h
117

These const-ness changes look independent and could land separately / ahead of time as NFC changes, independently of isValid() and whatever we end up with for FileEntryTest.

sammccall marked an inline comment as done.Apr 6 2022, 11:42 AM

The ugly part here:

  • FileEntryTest was constructing dummy FileEntrys to wrap in FileEntryRef
  • I changed this to use a FileManager as a factory

It's not clear *why* you changed this to use a FileManager as a factory. It seems unrelated to removing FileEntry::isValid() (but maybe I'm missing something obvious).

I removed the public default constructor of FileEntry, which was the one remaining way to create an invalid FileEntry.

Such a FileEntry is almost entirely useless, because it can never be put into a valid state and isn't useful as a sentinel value. However FileEntryTest does use them, being careful to only rely on their address.

It also doesn't seem like an improvement for the test, since FileManager is full of hacks and twisted logic that's hard to reason about

Agree. The test is suffering here in order to achieve a clean public API while keeping the basic structure of the test the same as before.

and it's useful to test FileEntry / FileEntryRef / etc. in isolation of that.

Yes, though the FileManager design doesn't support that very well. FileEntryRef method fields in FileEntry which can only be set by FileManager, so isolating the test means those can't be tested at all.

Depending on the goal, maybe instead we could abstract out some lower-level API, FileManagerBase or FileEntryFactory or something, which both FileEntryTest and FileManager use.

My goal is to make the API simpler to understand by eliminating states/APIs that aren't relevant to production code and confuse readers.

I think it's worth making the test a bit uglier to achieve that, and by contrast adding inheritance to FileManager would make it harder to understand.

Some ideas, do any seem acceptable?

  • have FileEntry friend class FileEntryTest or so
  • add static FileEntry FileEntry::createForTest() to replace the public default constructor
  • change this test to cover FM/FE/FER together
  • use FM as a factory as in this patch, but document it verbosely
  • make the constructor of FileEntry protected instead of private, and define a subclass for tests
benlangmuir added inline comments.Apr 6 2022, 11:44 AM
clang/unittests/Basic/FileEntryTest.cpp
47–52

Could we add friend class FileEntryTest to FileEntry to get access to the private constructor and go back to the original approach? I see some other places in llvm that use that pattern.

benlangmuir added inline comments.Apr 6 2022, 11:46 AM
clang/unittests/Basic/FileEntryTest.cpp
47–52

(just saw Sam made the same suggestion)

dexonsmith added inline comments.Apr 6 2022, 11:49 AM
clang/include/clang/Basic/FileEntry.h
332–334

Aha, now I understand why you needed a factory in the FileEntryTest: because you made the constructor private.

Instead, can we add an initializing constructor to FileEntry? It'd be fine for that to be public; it seems implausible for someone to misuse it.

clang/lib/Basic/FileManager.cpp
422–462

This dance'll be a bit different if there's an initializing constructor, but maybe it'd be cleaner anyway:

FileEntry **Slot = nullptr;
if (!getStat...) {
  Status = ...; // and update name in Status with fillRealPathName()
  Slot = &UniqueRealFiles[Status.getUniqueID()];
  if (*Slot) return early;
} else {
  Status = ...;
  VirtualFileEntries.push_back(nullptr);
  Slot = &VirtualFileEntries.back();
}
UFE = *Slot = new (FilesAlloc.Allocate()) FileEntry(Status, Dir, NextFileUID++);
NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo);
UFE->LastRef = UFE;
sammccall added inline comments.Apr 6 2022, 11:53 AM
clang/include/clang/Basic/FileEntry.h
117

Sure. In it's current form the patch requires these changes as we can't get a mutable FileEntry*.

I'll split them out.

clang/lib/Basic/FileManager.cpp
462–463

I happen to know this one :-)
Clang-format can support alignment between lines (e.g. of =). Removing line 2 from well-formatted code *can* cause spaces to need to be removed from line 1.
In this case, AlignConsecutiveAssignments is false in LLVM style, and the spaces were removed for an unrelated reason. But clang-format doesn't track causality. Getting it to preserve misformatting adjacent to modified code would be a bit of a project!

(Seeing the other replies now!)

I think it's worth making the test a bit uglier to achieve that, and by contrast adding inheritance to FileManager would make it harder to understand.

Some ideas, do any seem acceptable?

  • have FileEntry friend class FileEntryTest or so

This idea sounds good to me.

I also like the idea I just posted (change to an initializing constructor), but it's more work and I'm fine with the friend class FileEntryTest as a way forward if you'd prefer it.

sammccall updated this revision to Diff 421021.Apr 6 2022, 3:01 PM

Make test a friend of {File,Directory}Entry to avoid the FileManager-as-factory.
(A real constructor would be cleaner, but requires tricky FileManager changes).
Revert most of the related test changes. Had to rename the test helper so the
friend declaration is clearer.

Revert const changes. Test no longer needs them. I'm not sure they're better.

Remove operator< change which I landed separately.

dexonsmith accepted this revision.Apr 6 2022, 3:15 PM

LGTM; thanks for iterating on it.

benlangmuir accepted this revision.Apr 6 2022, 3:39 PM
This revision was landed with ongoing or failed builds.Apr 7 2022, 7:45 AM
This revision was automatically updated to reflect the committed changes.