diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2019-12-04 14:32:15 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2019-12-05 13:30:36 +0100 |
commit | 6a10149c5fef13721e3f83727a828556f8e1ec9a (patch) | |
tree | daf86b71c6bd3101d3586a12152e00408f934540 /compilerplugins/clang/pluginhandler.cxx | |
parent | e9e0ccae48385fb949c2c3f0aac678784ab14705 (diff) |
New loplugin:unusedmember
* See comment at head of compilerplugins/clang/unusedmember.cxx for description.
* Moved isAllRelevantCodeDefined from loplugin:fakebool to PluginHandler for
reuse. (Made it a member function so that it can reuse its two
RecordCompleteMap instances across different loplugins. Probably safer
lifecycle-wise to have them as PluginHandler members than to have them as
static local variables in function isAllRelevantCodeDefined.)
* Need Plugin::ignoreLocation overload for TypeLoc now, thanks to
UnusedMember::VisitElaboratedTypeLoc.
* UETT_PreferredAlignOf was split off UETT_AlignOf with <https://github.com/
llvm/llvm-project/commit/6822bd79ac43f267613f1615bf60407103e24dba> "PR26547:
alignof should return ABI alignment, not preferred alignment".
* RecursiveASTVisitor::TraverseAlignedAttr traverses into the attribute's
argument only since <https://github.com/llvm/llvm-project/commit/
f26d551387f032e05e5e6551605b150f38c3f5b2> "Do not look through pack
expansions when looking for unexpanded parameter packs".
Change-Id: Ic2702b03d4567fa2533333766de7920f3c524a69
Reviewed-on: https://gerrit.libreoffice.org/84416
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins/clang/pluginhandler.cxx')
-rw-r--r-- | compilerplugins/clang/pluginhandler.cxx | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/compilerplugins/clang/pluginhandler.cxx b/compilerplugins/clang/pluginhandler.cxx index 43c9fb33c1c6..6d00cf22a8cf 100644 --- a/compilerplugins/clang/pluginhandler.cxx +++ b/compilerplugins/clang/pluginhandler.cxx @@ -384,6 +384,112 @@ void PluginHandler::HandleTranslationUnit( ASTContext& context ) #endif } +namespace { + +// BEGIN code copied from LLVM's clang/lib/Sema/Sema.cpp + +/// Returns true, if all methods and nested classes of the given +/// CXXRecordDecl are defined in this translation unit. +/// +/// Should only be called from ActOnEndOfTranslationUnit so that all +/// definitions are actually read. +static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, + RecordCompleteMap &MNCComplete) { + RecordCompleteMap::iterator Cache = MNCComplete.find(RD); + if (Cache != MNCComplete.end()) + return Cache->second; + if (!RD->isCompleteDefinition()) + return false; + bool Complete = true; + for (DeclContext::decl_iterator I = RD->decls_begin(), + E = RD->decls_end(); + I != E && Complete; ++I) { + if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) + Complete = M->isDefined() || M->isDefaulted() || + (M->isPure() && !isa<CXXDestructorDecl>(M)); + else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) + // If the template function is marked as late template parsed at this + // point, it has not been instantiated and therefore we have not + // performed semantic analysis on it yet, so we cannot know if the type + // can be considered complete. + Complete = !F->getTemplatedDecl()->isLateTemplateParsed() && + F->getTemplatedDecl()->isDefined(); + else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) { + if (R->isInjectedClassName()) + continue; + if (R->hasDefinition()) + Complete = MethodsAndNestedClassesComplete(R->getDefinition(), + MNCComplete); + else + Complete = false; + } + } + MNCComplete[RD] = Complete; + return Complete; +} + +/// Returns true, if the given CXXRecordDecl is fully defined in this +/// translation unit, i.e. all methods are defined or pure virtual and all +/// friends, friend functions and nested classes are fully defined in this +/// translation unit. +/// +/// Should only be called from ActOnEndOfTranslationUnit so that all +/// definitions are actually read. +static bool IsRecordFullyDefined(const CXXRecordDecl *RD, + RecordCompleteMap &RecordsComplete, + RecordCompleteMap &MNCComplete) { + RecordCompleteMap::iterator Cache = RecordsComplete.find(RD); + if (Cache != RecordsComplete.end()) + return Cache->second; + bool Complete = MethodsAndNestedClassesComplete(RD, MNCComplete); + for (CXXRecordDecl::friend_iterator I = RD->friend_begin(), + E = RD->friend_end(); + I != E && Complete; ++I) { + // Check if friend classes and methods are complete. + if (TypeSourceInfo *TSI = (*I)->getFriendType()) { + // Friend classes are available as the TypeSourceInfo of the FriendDecl. + if (CXXRecordDecl *FriendD = TSI->getType()->getAsCXXRecordDecl()) + Complete = MethodsAndNestedClassesComplete(FriendD, MNCComplete); + else + Complete = false; + } else { + // Friend functions are available through the NamedDecl of FriendDecl. + if (const FunctionDecl *FD = + dyn_cast<FunctionDecl>((*I)->getFriendDecl())) + Complete = FD->isDefined(); + else + // This is a template friend, give up. + Complete = false; + } + } + RecordsComplete[RD] = Complete; + return Complete; +} + +// END code copied from LLVM's clang/lib/Sema/Sema.cpp + +} + +bool PluginHandler::isAllRelevantCodeDefined(NamedDecl const * decl) { + switch (decl->getAccess()) { + case AS_protected: + if (!cast<CXXRecordDecl>(decl->getDeclContext())->hasAttr<FinalAttr>()) { + break; + } + LLVM_FALLTHROUGH; + case AS_private: + if (IsRecordFullyDefined( + cast<CXXRecordDecl>(decl->getDeclContext()), RecordsComplete_, MNCComplete_)) + { + return true; + } + break; + default: + break; + } + return !decl->isExternallyVisible(); +} + std::unique_ptr<ASTConsumer> LibreOfficeAction::CreateASTConsumer( CompilerInstance& Compiler, StringRef ) { #if __cplusplus >= 201402L |