This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Don't complete ObjCInterfaceDecls in ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName
ClosedPublic

Authored by teemperor on May 26 2020, 7:30 AM.

Details

Summary

For ObjCInterfaceDecls, LLDB iterates over the methods of the interface in FindExternalVisibleDeclsByName
since commit ef423a3ba57045f80b0fcafce72121449a8b54d4 .
However, when LLDB calls oid->methods() in that function, Clang will pull in all declarations in the current
DeclContext from the current ExternalASTSource (which is again, ClangExternalASTSourceCallbacks). The
reason for that is that methods() is just a wrapper for decls() which is supposed to provide a list of *all*
(both currently loaded and external) decls in the DeclContext.

However, ClangExternalASTSourceCallbacks::FindExternalLexicalDecls doesn't implement support for ObjCInterfaceDecl,
so we don't actually add any declarations and just mark the ObjCInterfaceDecl as having no ExternalLexicalStorage.

As LLDB uses the ExternalLexicalStorage to see if it can complete a type with the ExternalASTSource, this causes
that LLDB thinks our class can't be completed any further by the ExternalASTSource
and will from on no longer make any CompleteType/FindExternalLexicalDecls calls to that decl. This essentially
renders those types unusable in the expression parser as they will always be considered incomplete.

This patch just changes the call to methods (which is just a decls() wrapper), to some ad-hoc noload_methods
call which is wrapping noload_decls(). noload_decls() won't trigger any calls to the ExternalASTSource, so
this prevents that ExternalLexicalStorage will be set to false.

The test for this is just adding a method to an ObjC interface. Before this patch, this unset the ExternalLexicalStorage
flag and put the interface into the state described above.

In a normal user session this situation was triggered by setting a breakpoint in a method of some ObjC class. This
caused LLDB to create the MethodDecl for that specific method and put it into the the ObjCInterfaceDecl.
Also ObjCLanguageRuntime::LookupInCompleteClassCache needs to be unable to resolve the type do
an actual definition when the breakpoint is set (I'm not sure how exactly this can happen, but we just
found no Type instance that had the TypePayloadClang::IsCompleteObjCClass flag set in its payload in
the situation where this happens. This however doesn't seem to be a regression as logic wasn't changed
from what I can see).

The module-ownership.mm test had to be changed as the only reason why the ObjC interface in that test had
it's ExternalLexicalStorage flag set to false was because of this unintended side effect. What actually happens
in the test is that ExternalLexicalStorage is first set to false in DWARFASTParserClang::CompleteTypeFromDWARF
when we try to complete the SomeClass interface, but is then the flag is set back to true once we add
the last ivar of SomeClass (see SetMemberOwningModule in TypeSystemClang.cpp which is called
when we add the ivar). I'll fix the code for that in a follow-up patch.

I think some of the code here needs some rethinking. LLDB and Clang shouldn't infer anything about the ExternalASTSource
and its ability to complete the current type form the ExternalLexicalStorage flag. We probably should
also actually provide any declarations when we get asked for the lexical decls of an ObjCInterfaceDecl. But both of those
changes are bigger (and most likely would cause us to eagerly complete more types), so those will be follow up patches
and this patch just brings us back to the state before commit ef423a3ba57045f80b0fcafce72121449a8b54d4 .

Fixes rdar://63584164

Diff Detail

Event Timeline

teemperor created this revision.May 26 2020, 7:30 AM
aprantl accepted this revision.May 26 2020, 11:04 AM

This sounds like it is in the spirit of the API, yes. Thanks!

This revision is now accepted and ready to land.May 26 2020, 11:04 AM

Great analysis.

So do we still need the changes in SetMemberOwningModule that set setHasExternalVisibleStorage and setHasExternalLexicalStorage?

So do we still need the changes in SetMemberOwningModule that set setHasExternalVisibleStorage and setHasExternalLexicalStorage?

That's a good point. I think that is the fix to get the module-ownership test working as intended (haven't tested that though). But not setting ExternalLexicalStorage can have bad consequences while having it set by accident should only be a small performance hit (as we will do the round-trip over SymbolFile that should early-exit on decls it already completed). So I think we should fix this in the follow-up commits and only try avoid unsetting ExternalLexicalStorage for this patch that gets back ported.

shafik accepted this revision.May 26 2020, 1:16 PM

It is fine to look at SetMemberOwningModule in a follow-up PR. I am not concerned from a performance perspective but just leaving around unnecessary code that will just confuse someone later on. If it is not needed anymore we should remove ASAP.

This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptMay 27 2020, 3:44 AM