File indexing completed on 2024-05-19 05:41:44
0001 /* 0002 SPDX-FileCopyrightText: 2023 Ahmad Samir <a.samirh78@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "sanitize-inline-keyword.h" 0008 0009 #include "ClazyContext.h" 0010 #include "FixItUtils.h" 0011 #include "HierarchyUtils.h" 0012 #include "QtUtils.h" 0013 #include "TypeUtils.h" 0014 #include "Utils.h" 0015 0016 #include <clang/AST/AST.h> 0017 #include <clang/Lex/Token.h> 0018 0019 using namespace std::string_literals; 0020 using namespace clang; 0021 0022 SanitizeInlineKeyword::SanitizeInlineKeyword(const std::string &name, ClazyContext *context) 0023 : CheckBase(name, context, Option_CanIgnoreIncludes) 0024 { 0025 } 0026 0027 void SanitizeInlineKeyword::VisitDecl(Decl *decl) 0028 { 0029 auto *member = dyn_cast<CXXMethodDecl>(decl); 0030 if (!member) { 0031 return; 0032 } 0033 0034 // The class this method belongs to 0035 auto *parentDecl = member->getParent(); 0036 // Only exported classes 0037 if (!parentDecl || parentDecl->getVisibility() == clang::HiddenVisibility) { 0038 return; 0039 } 0040 0041 // constexpr methods are implicitly inline 0042 if (member->isConstexpr()) { 0043 return; 0044 } 0045 // Function templates are implicitly inline 0046 if (member->isTemplateDecl()) { 0047 return; 0048 } 0049 0050 // Is this CXXMethodDecl* inside the class body? 0051 if (member->isOutOfLine()) { 0052 return; 0053 } 0054 0055 // Declared/defined in-class 0056 if (member->isThisDeclarationADefinition()) { 0057 return; 0058 } 0059 0060 FunctionDecl *definition = member->getDefinition(); 0061 if (!definition) 0062 return; 0063 0064 auto name = clazy::name(definition); 0065 0066 auto *cxxDefinition = dyn_cast<CXXMethodDecl>(definition); 0067 if (!cxxDefinition) { 0068 return; 0069 } 0070 0071 if (name.empty()) { 0072 name = clazy::name(cxxDefinition); // E.g. operator[] 0073 } 0074 0075 if (name.empty()) { 0076 return; // Can't emit a warning without a method name 0077 } 0078 0079 auto defHasInline = [](auto def) { 0080 return def->isInlineSpecified() && def->isThisDeclarationADefinition() && def->isOutOfLine(); 0081 }; 0082 0083 if (!member->isInlineSpecified() && defHasInline(cxxDefinition)) { 0084 std::string msg = std::string(name) + "(): " 0085 + "the 'inline' keyword is specified on the definition, but not the declaration. " 0086 "This could lead to hard-to-suppress warnings with some compilers (e.g. MinGW). " 0087 "The 'inline' keyword should be used for the declaration only."; 0088 0089 SourceLocation loc = member->getBeginLoc(); 0090 std::vector<FixItHint> fixits{clazy::createInsertion(loc, "inline "s)}; 0091 0092 SourceLocation def = cxxDefinition->getBeginLoc(); 0093 SourceLocation defEnd = cxxDefinition->getEndLoc(); 0094 Token tok; 0095 for (; def.isValid() && def != defEnd; def = Utils::locForNextToken(def, sm(), lo())) { 0096 if (!Lexer::getRawToken(def, tok, sm(), lo())) { // false means success! 0097 if (tok.is(tok::raw_identifier) && tok.getRawIdentifier() == "inline"s) { 0098 // Remove 'inline' from the definition 0099 fixits.emplace_back(clazy::createReplacement(def, std::string())); 0100 break; 0101 } 0102 } 0103 } 0104 0105 emitWarning(loc, msg, fixits); 0106 } 0107 }