diff options
Diffstat (limited to 'clang-tools-extra')
18 files changed, 1350 insertions, 33 deletions
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 79850e1..929112f 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -502,13 +502,13 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, } void ScopeChildren::sort() { - llvm::sort(Namespaces.begin(), Namespaces.end()); - llvm::sort(Records.begin(), Records.end()); - llvm::sort(Functions.begin(), Functions.end()); - llvm::sort(Enums.begin(), Enums.end()); - llvm::sort(Typedefs.begin(), Typedefs.end()); - llvm::sort(Concepts.begin(), Concepts.end()); - llvm::sort(Variables.begin(), Variables.end()); + llvm::sort(Namespaces); + llvm::sort(Records); + llvm::sort(Functions); + llvm::sort(Enums); + llvm::sort(Typedefs); + llvm::sort(Concepts); + llvm::sort(Variables); } } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt index 4f1da43..41386cd 100644 --- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt @@ -17,7 +17,6 @@ add_clang_library(clangTidyLLVMModule STATIC clangTidy clangTidyReadabilityModule clangTidyUtils - clangTransformer DEPENDS omp_gen @@ -31,4 +30,5 @@ clang_target_link_libraries(clangTidyLLVMModule clangBasic clangLex clangTooling + clangTransformer ) diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp index 0b28ea2..4722199 100644 --- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp @@ -111,17 +111,23 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector Builder, } RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { - return makeRule( + Stencil message = cat("use 'OpType::create(builder, ...)' instead of " + "'builder.create<OpType>(...)'"); + // Match a create call on an OpBuilder. + ast_matchers::internal::Matcher<Stmt> base = cxxMemberCallExpr( on(expr(hasType( cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder")))) .bind("builder")), callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))), callee(cxxMethodDecl(hasName("create")))) - .bind("call"), - rewrite(node("call"), node("builder"), callArgs("call")), - cat("use 'OpType::create(builder, ...)' instead of " - "'builder.create<OpType>(...)'")); + .bind("call"); + return applyFirst( + // Attempt rewrite given an lvalue builder, else just warn. + {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base), + rewrite(node("call"), node("builder"), callArgs("call")), + message), + makeRule(base, noopEdit(node("call")), message)}); } } // namespace diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp index 7ea9676..bb8fb240 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp @@ -121,10 +121,11 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) { hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl())))); Finder->addMatcher( initListExpr( - hasType(cxxRecordDecl( - RestrictToPODTypes ? isPOD() : isAggregate(), - unless(anyOf(HasBaseWithFields, hasName("::std::array")))) - .bind("type")), + hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( + cxxRecordDecl( + RestrictToPODTypes ? isPOD() : isAggregate(), + unless(anyOf(HasBaseWithFields, hasName("::std::array")))) + .bind("type"))))), IgnoreSingleElementAggregates ? hasMoreThanOneElement() : anything(), unless(isFullyDesignated())) .bind("init"), @@ -155,7 +156,7 @@ void UseDesignatedInitializersCheck::check( DiagnosticBuilder Diag = diag(InitList->getLBraceLoc(), "use designated initializer list to initialize %0"); - Diag << Type << InitList->getSourceRange(); + Diag << InitList->getType() << InitList->getSourceRange(); for (const Stmt *InitExpr : *SyntacticInitList) { const auto Designator = Designators[InitExpr->getBeginLoc()]; if (Designator && !Designator->empty()) diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 936a906..e307339 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -92,7 +92,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { const LangOptions &LO = getLangOpts(); // Match CXXRecordDecl only to store the range of the last non-implicit full - // declaration, to later check whether it's within the typdef itself. + // declaration, to later check whether it's within the typedef itself. const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName); if (MatchedTagDecl) { // It is not sufficient to just track the last TagDecl that we've seen, @@ -152,7 +152,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { StringRef ExtraReference = ""; if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) { // Each type introduced in a typedef can specify being a reference or - // pointer type seperately, so we need to sigure out if the new using-decl + // pointer type separately, so we need to figure out if the new using-decl // needs to be to a reference or pointer as well. const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind( MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star, diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index 91a08b9..561f067 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -106,12 +106,14 @@ QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name, : ClangTidyCheck(Name, Context), AddConstToQualified(Options.get("AddConstToQualified", true)), AllowedTypes( - utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} + utils::options::parseStringList(Options.get("AllowedTypes", ""))), + IgnoreAliasing(Options.get("IgnoreAliasing", true)) {} void QualifiedAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AddConstToQualified", AddConstToQualified); Options.store(Opts, "AllowedTypes", utils::options::serializeStringList(AllowedTypes)); + Options.store(Opts, "IgnoreAliasing", IgnoreAliasing); } void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { @@ -134,16 +136,30 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { auto IsBoundToType = refersToType(equalsBoundNode("type")); auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); - auto IsAutoDeducedToPointer = [](const std::vector<StringRef> &AllowedTypes, - const auto &...InnerMatchers) { - return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))), - unless(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))), - unless(pointerType(pointee(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + + auto IsPointerType = [this](const auto &...InnerMatchers) { + if (this->IgnoreAliasing) { + return qualType( + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))); + } else { + return qualType( + anyOf(qualType(pointerType(pointee(InnerMatchers...))), + qualType(substTemplateTypeParmType(hasReplacementType( + pointerType(pointee(InnerMatchers...))))))); + } }; + auto IsAutoDeducedToPointer = + [IsPointerType](const std::vector<StringRef> &AllowedTypes, + const auto &...InnerMatchers) { + return autoType(hasDeducedType( + IsPointerType(InnerMatchers...), + unless(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))), + unless(pointerType(pointee(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + }; + Finder->addMatcher( ExplicitSingleVarDecl( hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)), diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h index 187a4cd..b5b713f 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h @@ -32,6 +32,7 @@ public: private: const bool AddConstToQualified; const std::vector<StringRef> AllowedTypes; + const bool IgnoreAliasing; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 59475b0..1d6e380 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -14,9 +14,9 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangDaemonTweaks OBJECT AddUsing.cpp AnnotateHighlightings.cpp - DumpAST.cpp DefineInline.cpp DefineOutline.cpp + DumpAST.cpp ExpandDeducedType.cpp ExpandMacro.cpp ExtractFunction.cpp @@ -24,6 +24,7 @@ add_clang_library(clangDaemonTweaks OBJECT MemberwiseConstructor.cpp ObjCLocalizeStringLiteral.cpp ObjCMemberwiseInitializer.cpp + OverridePureVirtuals.cpp PopulateSwitch.cpp RawStringLiteral.cpp RemoveUsingNamespace.cpp diff --git a/clang-tools-extra/clangd/refactor/tweaks/OverridePureVirtuals.cpp b/clang-tools-extra/clangd/refactor/tweaks/OverridePureVirtuals.cpp new file mode 100644 index 0000000..16febec --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/OverridePureVirtuals.cpp @@ -0,0 +1,374 @@ +//===--- OverridePureVirtuals.cpp --------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Tweak to automatically generate stubs for pure virtual methods inherited from +// base classes. +// +// Purpose: +// - Simplifies making a derived class concrete by automating the creation of +// required method overrides from abstract bases. +// +// Tweak Summary: +// +// 1. Activation Conditions (prepare): +// - The tweak activates when the cursor is over a C++ class definition. +// - The class must be abstract (it, or its base classes, have unimplemented +// pure virtual functions). +// - It must also inherit from at least one other abstract class. +// +// 2. Identifying Missing Methods: +// - The tweak scans the inheritance hierarchy of the current class. +// - It identifies all unique pure virtual methods from base classes +// that are not yet implemented or overridden. +// - These missing methods are then grouped by their original access +// specifier (e.g., public, protected). +// +// 3. Code Generation and Insertion: +// - For each group of missing methods, stubs are inserted. +// - If an access specifier section (like `public:`) exists, stubs are +// inserted there; otherwise, a new section is created and appended. +// - Each generated stub includes the `override` keyword, a `// TODO:` +// comment, and a `static_assert(false, ...)` to force a compile-time +// error if the method remains unimplemented. +// - The base method's signature is adjusted (e.g., `virtual` and `= 0` +// are removed for the override). +// +// 4. Code Action Provided: +// - A single code action titled "Override pure virtual methods" is offered. +// - Applying this action results in a single source file modification +// containing all the generated method stubs. +// +// Example: +// +// class Base { +// public: +// virtual void publicMethod() = 0; +// protected: +// virtual auto privateMethod() const -> int = 0; +// }; +// +// Before: +// // cursor here +// class Derived : public Base {}^; +// +// After: +// +// class Derived : public Base { +// public: +// void publicMethod() override { +// // TODO: Implement this pure virtual method. +// static_assert(false, "Method `publicMethod` is not implemented."); +// } +// +// protected: +// auto privateMethod() const -> int override { +// // TODO: Implement this pure virtual method. +// static_assert(false, "Method `privateMethod` is not implemented."); +// } +// }; +// +//===----------------------------------------------------------------------===// + +#include "refactor/Tweak.h" +#include "support/Token.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/FormatVariadic.h" +#include <string> + +namespace clang { +namespace clangd { +namespace { + +// This function removes the "virtual" and the "= 0" at the end; +// e.g.: +// "virtual void foo(int var = 0) = 0" // input. +// "void foo(int var = 0)" // output. +std::string removePureVirtualSyntax(const std::string &MethodDecl, + const LangOptions &LangOpts) { + assert(!MethodDecl.empty()); + + TokenStream TS = lex(MethodDecl, LangOpts); + + std::string DeclString; + for (const clangd::Token &Tk : TS.tokens()) { + if (Tk.Kind == clang::tok::raw_identifier && Tk.text() == "virtual") + continue; + + // If the ending two tokens are "= 0", we break here and we already have the + // method's string without the pure virtual syntax. + const auto &Next = Tk.next(); + if (Next.next().Kind == tok::eof && Tk.Kind == clang::tok::equal && + Next.text() == "0") + break; + + DeclString += Tk.text(); + if (Tk.Kind != tok::l_paren && Next.Kind != tok::comma && + Next.Kind != tok::r_paren && Next.Kind != tok::l_paren) + DeclString += ' '; + } + // Trim the last whitespace. + if (DeclString.back() == ' ') + DeclString.pop_back(); + + return DeclString; +} + +class OverridePureVirtuals final : public Tweak { +public: + const char *id() const final; // defined by REGISTER_TWEAK. + bool prepare(const Selection &Sel) override; + Expected<Effect> apply(const Selection &Sel) override; + std::string title() const override { return "Override pure virtual methods"; } + llvm::StringLiteral kind() const override { + return CodeAction::QUICKFIX_KIND; + } + +private: + // Stores the CXXRecordDecl of the class being modified. + const CXXRecordDecl *CurrentDeclDef = nullptr; + // Stores pure virtual methods that need overriding, grouped by their original + // access specifier. + llvm::MapVector<AccessSpecifier, llvm::SmallVector<const CXXMethodDecl *>> + MissingMethodsByAccess; + // Stores the source locations of existing access specifiers in CurrentDecl. + llvm::MapVector<AccessSpecifier, SourceLocation> AccessSpecifierLocations; + // Helper function to gather information before applying the tweak. + void collectMissingPureVirtuals(); +}; + +REGISTER_TWEAK(OverridePureVirtuals) + +// Function to get all unique pure virtual methods from the entire +// base class hierarchy of CurrentDeclDef. +llvm::SmallVector<const clang::CXXMethodDecl *> +getAllUniquePureVirtualsFromBaseHierarchy( + const clang::CXXRecordDecl *CurrentDeclDef) { + llvm::SmallVector<const clang::CXXMethodDecl *> AllPureVirtualsInHierarchy; + llvm::DenseSet<const clang::CXXMethodDecl *> CanonicalPureVirtualsSeen; + + if (!CurrentDeclDef || !CurrentDeclDef->getDefinition()) + return AllPureVirtualsInHierarchy; + + const clang::CXXRecordDecl *Def = CurrentDeclDef->getDefinition(); + + Def->forallBases([&](const clang::CXXRecordDecl *BaseDefinition) { + for (const clang::CXXMethodDecl *Method : BaseDefinition->methods()) { + if (Method->isPureVirtual() && + CanonicalPureVirtualsSeen.insert(Method->getCanonicalDecl()).second) + AllPureVirtualsInHierarchy.emplace_back(Method); + } + // Continue iterating through all bases. + return true; + }); + + return AllPureVirtualsInHierarchy; +} + +// Gets canonical declarations of methods already overridden or implemented in +// class D. +llvm::SetVector<const CXXMethodDecl *> +getImplementedOrOverriddenCanonicals(const CXXRecordDecl *D) { + llvm::SetVector<const CXXMethodDecl *> ImplementedSet; + for (const CXXMethodDecl *M : D->methods()) { + // If M provides an implementation for any virtual method it overrides. + // A method is an "implementation" if it's virtual and not pure. + // Or if it directly overrides a base method. + for (const CXXMethodDecl *OverriddenM : M->overridden_methods()) + ImplementedSet.insert(OverriddenM->getCanonicalDecl()); + } + return ImplementedSet; +} + +// Get the location of every colon of the `AccessSpecifier`. +llvm::MapVector<AccessSpecifier, SourceLocation> +getSpecifierLocations(const CXXRecordDecl *D) { + llvm::MapVector<AccessSpecifier, SourceLocation> Locs; + for (auto *DeclNode : D->decls()) { + if (const auto *ASD = llvm::dyn_cast<AccessSpecDecl>(DeclNode)) + Locs[ASD->getAccess()] = ASD->getColonLoc(); + } + return Locs; +} + +bool hasAbstractBaseAncestor(const clang::CXXRecordDecl *CurrentDecl) { + assert(CurrentDecl && CurrentDecl->getDefinition()); + + return llvm::any_of( + CurrentDecl->getDefinition()->bases(), [](CXXBaseSpecifier BaseSpec) { + const auto *D = BaseSpec.getType()->getAsCXXRecordDecl(); + const auto *Def = D ? D->getDefinition() : nullptr; + return Def && Def->isAbstract(); + }); +} + +// The tweak is available if the selection is over an abstract C++ class +// definition that also inherits from at least one other abstract class. +bool OverridePureVirtuals::prepare(const Selection &Sel) { + const SelectionTree::Node *Node = Sel.ASTSelection.commonAncestor(); + if (!Node) + return false; + + // Make sure we have a definition. + CurrentDeclDef = Node->ASTNode.get<CXXRecordDecl>(); + if (!CurrentDeclDef || !CurrentDeclDef->getDefinition()) + return false; + + // From now on, we should work with the definition. + CurrentDeclDef = CurrentDeclDef->getDefinition(); + + // Only offer for abstract classes with abstract bases. + return CurrentDeclDef->isAbstract() && + hasAbstractBaseAncestor(CurrentDeclDef); +} + +// Collects all pure virtual methods from base classes that `CurrentDeclDef` has +// not yet overridden, grouped by their original access specifier. +// +// Results are stored in `MissingMethodsByAccess` and `AccessSpecifierLocations` +// is also populated. +void OverridePureVirtuals::collectMissingPureVirtuals() { + if (!CurrentDeclDef) + return; + + AccessSpecifierLocations = getSpecifierLocations(CurrentDeclDef); + MissingMethodsByAccess.clear(); + + // Get all unique pure virtual methods from the entire base class hierarchy. + llvm::SmallVector<const CXXMethodDecl *> AllPureVirtualsInHierarchy = + getAllUniquePureVirtualsFromBaseHierarchy(CurrentDeclDef); + + // Get methods already implemented or overridden in CurrentDecl. + const auto ImplementedOrOverriddenSet = + getImplementedOrOverriddenCanonicals(CurrentDeclDef); + + // Filter AllPureVirtualsInHierarchy to find those not in + // ImplementedOrOverriddenSet, which needs to be overriden. + for (const CXXMethodDecl *BaseMethod : AllPureVirtualsInHierarchy) { + bool AlreadyHandled = ImplementedOrOverriddenSet.contains(BaseMethod); + if (!AlreadyHandled) + MissingMethodsByAccess[BaseMethod->getAccess()].emplace_back(BaseMethod); + } +} + +std::string generateOverrideString(const CXXMethodDecl *Method, + const LangOptions &LangOpts) { + std::string MethodDecl; + auto OS = llvm::raw_string_ostream(MethodDecl); + Method->print(OS); + + return llvm::formatv( + "\n {0} override {{\n" + " // TODO: Implement this pure virtual method.\n" + " static_assert(false, \"Method `{1}` is not implemented.\");\n" + " }", + removePureVirtualSyntax(MethodDecl, LangOpts), Method->getName()) + .str(); +} + +// Free function to generate the string for a group of method overrides. +std::string generateOverridesStringForGroup( + llvm::SmallVector<const CXXMethodDecl *> Methods, + const LangOptions &LangOpts) { + llvm::SmallVector<std::string> MethodsString; + MethodsString.reserve(Methods.size()); + + for (const CXXMethodDecl *Method : Methods) { + MethodsString.emplace_back(generateOverrideString(Method, LangOpts)); + } + + return llvm::join(MethodsString, "\n") + '\n'; +} + +Expected<Tweak::Effect> OverridePureVirtuals::apply(const Selection &Sel) { + // The correctness of this tweak heavily relies on the accurate population of + // these members. + collectMissingPureVirtuals(); + // The `prepare` should prevent this. If the prepare identifies an abstract + // method, then is must have missing methods. + assert(!MissingMethodsByAccess.empty()); + + const auto &SM = Sel.AST->getSourceManager(); + const auto &LangOpts = Sel.AST->getLangOpts(); + + tooling::Replacements EditReplacements; + // Stores text for new access specifier sections that are not already present + // in the class. + // Example: + // public: // ... + // protected: // ... + std::string NewSectionsToAppendText; + + for (const auto &[AS, Methods] : MissingMethodsByAccess) { + assert(!Methods.empty()); + + std::string MethodsGroupString = + generateOverridesStringForGroup(Methods, LangOpts); + + auto *ExistingSpecLocIter = AccessSpecifierLocations.find(AS); + bool ASExists = ExistingSpecLocIter != AccessSpecifierLocations.end(); + if (ASExists) { + // Access specifier section already exists in the class. + // Get location immediately *after* the colon. + SourceLocation InsertLoc = + ExistingSpecLocIter->second.getLocWithOffset(1); + + // Create a replacement to insert the method declarations. + // The replacement is at InsertLoc, has length 0 (insertion), and uses + // InsertionText. + std::string InsertionText = MethodsGroupString; + tooling::Replacement Rep(SM, InsertLoc, 0, InsertionText); + if (auto Err = EditReplacements.add(Rep)) + return llvm::Expected<Tweak::Effect>(std::move(Err)); + } else { + // Access specifier section does not exist in the class. + // These methods will be grouped into NewSectionsToAppendText and added + // towards the end of the class definition. + NewSectionsToAppendText += + getAccessSpelling(AS).str() + ':' + MethodsGroupString; + } + } + + // After processing all access specifiers, add any newly created sections + // (stored in NewSectionsToAppendText) to the end of the class. + if (!NewSectionsToAppendText.empty()) { + // AppendLoc is the SourceLocation of the closing brace '}' of the class. + // The replacement will insert text *before* this closing brace. + SourceLocation AppendLoc = CurrentDeclDef->getBraceRange().getEnd(); + std::string FinalAppendText = std::move(NewSectionsToAppendText); + + if (!CurrentDeclDef->decls_empty() || !EditReplacements.empty()) { + FinalAppendText = '\n' + FinalAppendText; + } + + // Create a replacement to append the new sections. + tooling::Replacement Rep(SM, AppendLoc, 0, FinalAppendText); + if (auto Err = EditReplacements.add(Rep)) + return llvm::Expected<Tweak::Effect>(std::move(Err)); + } + + if (EditReplacements.empty()) { + return llvm::make_error<llvm::StringError>( + "No changes to apply (internal error or no methods generated).", + llvm::inconvertibleErrorCode()); + } + + // Return the collected replacements as the effect of this tweak. + return Effect::mainFileEdit(SM, EditReplacements); +} + +} // namespace +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt index dffdcd5..d425070 100644 --- a/clang-tools-extra/clangd/unittests/CMakeLists.txt +++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -131,6 +131,7 @@ add_unittest(ClangdUnitTests ClangdTests tweaks/MemberwiseConstructorTests.cpp tweaks/ObjCLocalizeStringLiteralTests.cpp tweaks/ObjCMemberwiseInitializerTests.cpp + tweaks/OverridePureVirtualsTests.cpp tweaks/PopulateSwitchTests.cpp tweaks/RawStringLiteralTests.cpp tweaks/RemoveUsingNamespaceTests.cpp diff --git a/clang-tools-extra/clangd/unittests/tweaks/OverridePureVirtualsTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/OverridePureVirtualsTests.cpp new file mode 100644 index 0000000..b7dcbee --- /dev/null +++ b/clang-tools-extra/clangd/unittests/tweaks/OverridePureVirtualsTests.cpp @@ -0,0 +1,720 @@ +//===-- OverridePureVirtualsTests.cpp ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TweakTesting.h" +#include "gtest/gtest.h" + +namespace clang { +namespace clangd { +namespace { + +class OverridePureVirtualsTests : public TweakTest { +protected: + OverridePureVirtualsTests() : TweakTest("OverridePureVirtuals") {} +}; + +TEST_F(OverridePureVirtualsTests, MinimalUnavailable) { + EXPECT_UNAVAILABLE("class ^C {};"); +} + +TEST_F(OverridePureVirtualsTests, MinimalAvailable) { + EXPECT_AVAILABLE(R"cpp( +class B { public: virtual void Foo() = 0; }; +class ^C : public B {}; +)cpp"); +} + +TEST_F(OverridePureVirtualsTests, UnavailableWhenOverriden) { + EXPECT_UNAVAILABLE( + R"cpp( +class B { +public: + virtual void foo() = 0; +}; + +class ^D : public B { +public: + void foo() override; +}; +)cpp"); +} + +TEST_F(OverridePureVirtualsTests, AvailabilityNoOverride) { + EXPECT_AVAILABLE(R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2() = 0; +}; + +class ^Derived : public Base { +public: +}; + +)cpp"); +} + +TEST_F(OverridePureVirtualsTests, AvailabilityPartiallyOverridden) { + EXPECT_AVAILABLE(R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2() = 0; +}; + +class ^Derived : public Base { +public: +void F1() override; +}; +)cpp"); +} + +TEST_F(OverridePureVirtualsTests, EmptyDerivedClass) { + const char *Before = R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2(int P1, const int &P2) = 0; +}; + +class ^Derived : public Base {}; +)cpp"; + const auto *Expected = R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2(int P1, const int &P2) = 0; +}; + +class Derived : public Base { +public: + void F1() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `F1` is not implemented."); + } + + void F2(int P1, const int & P2) override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `F2` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, SingleBaseClassPartiallyImplemented) { + auto Applied = apply( + R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2() = 0; +}; + +class ^Derived : public Base { +public: + void F1() override; +}; +)cpp"); + + const auto *Expected = R"cpp( +class Base { +public: +virtual ~Base() = default; +virtual void F1() = 0; +virtual void F2() = 0; +}; + +class Derived : public Base { +public: + void F2() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `F2` is not implemented."); + } + + void F1() override; +}; +)cpp"; + EXPECT_EQ(Applied, Expected) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, MultipleDirectBaseClasses) { + const char *Before = R"cpp( +class Base1 { +public: + virtual void func1() = 0; +}; +class Base2 { +protected: + virtual bool func2(char c) const = 0; +}; + +class ^Derived : public Base1, public Base2 {}; +)cpp"; + const auto *Expected = R"cpp( +class Base1 { +public: + virtual void func1() = 0; +}; +class Base2 { +protected: + virtual bool func2(char c) const = 0; +}; + +class Derived : public Base1, public Base2 { +public: + void func1() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `func1` is not implemented."); + } +protected: + bool func2(char c) const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `func2` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, UnnamedParametersInBase) { + const char *Before = R"cpp( +struct S {}; +class Base { +public: + virtual void func(int, const S&, char*) = 0; +}; + +class ^Derived : public Base {}; +)cpp"; + + const auto *Expected = R"cpp( +struct S {}; +class Base { +public: + virtual void func(int, const S&, char*) = 0; +}; + +class Derived : public Base { +public: + void func(int, const S &, char *) override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `func` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, DiamondInheritance) { + const char *Before = R"cpp( +class Top { +public: + virtual ~Top() = default; + virtual void diamond_func() = 0; +}; +class Left : virtual public Top {}; +class Right : virtual public Top {}; +class ^Bottom : public Left, public Right {}; +)cpp"; + const auto *Expected = R"cpp( +class Top { +public: + virtual ~Top() = default; + virtual void diamond_func() = 0; +}; +class Left : virtual public Top {}; +class Right : virtual public Top {}; +class Bottom : public Left, public Right { +public: + void diamond_func() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `diamond_func` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, MixedAccessSpecifiers) { + const char *Before = R"cpp( +class Base { +public: + virtual void pub_func() = 0; + virtual void pub_func2(char) const = 0; +protected: + virtual int prot_func(int x) const = 0; +}; + +class ^Derived : public Base { + int member; // Existing member +public: + Derived(int m) : member(m) {} +}; +)cpp"; + const auto *Expected = R"cpp( +class Base { +public: + virtual void pub_func() = 0; + virtual void pub_func2(char) const = 0; +protected: + virtual int prot_func(int x) const = 0; +}; + +class Derived : public Base { + int member; // Existing member +public: + void pub_func() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `pub_func` is not implemented."); + } + + void pub_func2(char) const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `pub_func2` is not implemented."); + } + + Derived(int m) : member(m) {} + +protected: + int prot_func(int x) const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `prot_func` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, OutOfOrderMixedAccessSpecifiers) { + const char *Before = R"cpp( +class Base { +public: + virtual void pub_func() = 0; + virtual void pub_func2(char) const = 0; +protected: + virtual int prot_func(int x) const = 0; +}; + +class ^Derived : public Base { + int member; // Existing member +protected: + void foo(); +public: + Derived(int m) : member(m) {} +}; +)cpp"; + const auto *Expected = R"cpp( +class Base { +public: + virtual void pub_func() = 0; + virtual void pub_func2(char) const = 0; +protected: + virtual int prot_func(int x) const = 0; +}; + +class Derived : public Base { + int member; // Existing member +protected: + int prot_func(int x) const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `prot_func` is not implemented."); + } + + void foo(); +public: + void pub_func() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `pub_func` is not implemented."); + } + + void pub_func2(char) const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `pub_func2` is not implemented."); + } + + Derived(int m) : member(m) {} +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, MultiAccessSpecifiersOverride) { + constexpr auto Before = R"cpp( +class Base { +public: + virtual void foo() = 0; +protected: + virtual void bar() = 0; +}; + +class ^Derived : public Base {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class Base { +public: + virtual void foo() = 0; +protected: + virtual void bar() = 0; +}; + +class Derived : public Base { +public: + void foo() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `foo` is not implemented."); + } +protected: + void bar() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `bar` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, AccessSpecifierAlreadyExisting) { + const char *Before = R"cpp( +class Base { +public: + virtual void func1() = 0; +}; + +class ^Derived : public Base { +public: +}; +)cpp"; + + const auto *Expected = R"cpp( +class Base { +public: + virtual void func1() = 0; +}; + +class Derived : public Base { +public: + void func1() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `func1` is not implemented."); + } + +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, ConstexprSpecifier) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + constexpr virtual int getValue() const = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + constexpr virtual int getValue() const = 0; +}; + +class D : public B { +public: + constexpr int getValue() const override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `getValue` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, ConstevalSpecifier) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + virtual consteval float calculate() = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual consteval float calculate() = 0; +}; + +class D : public B { +public: + consteval float calculate() override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `calculate` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, LValueRefQualifier) { + constexpr auto Before = R"cpp( +class B { +public: + virtual void process() & = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual void process() & = 0; +}; + +class D : public B { +public: + void process() & override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `process` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, RValueRefQualifier) { + constexpr auto Before = R"cpp( +class B { +public: + virtual bool isValid() && = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual bool isValid() && = 0; +}; + +class D : public B { +public: + bool isValid() && override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `isValid` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, SimpleTrailingReturnType) { + constexpr auto Before = R"cpp( +class B { +public: + virtual auto getStatus() -> bool = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual auto getStatus() -> bool = 0; +}; + +class D : public B { +public: + auto getStatus() -> bool override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `getStatus` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, ConstexprLValueRefAndTrailingReturn) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + constexpr virtual auto getData() & -> const char * = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + constexpr virtual auto getData() & -> const char * = 0; +}; + +class D : public B { +public: + constexpr auto getData() & -> const char * override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `getData` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, ConstevalRValueRefAndTrailingReturn) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + virtual consteval auto foo() && -> double = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual consteval auto foo() && -> double = 0; +}; + +class D : public B { +public: + consteval auto foo() && -> double override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `foo` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, CombinedFeaturesWithTrailingReturnTypes) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + virtual auto f1() & -> int = 0; + constexpr virtual auto f2() && -> int = 0; + virtual consteval auto f3() -> int = 0; + virtual auto f4() const & -> char = 0; + constexpr virtual auto f5() const && -> bool = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual auto f1() & -> int = 0; + constexpr virtual auto f2() && -> int = 0; + virtual consteval auto f3() -> int = 0; + virtual auto f4() const & -> char = 0; + constexpr virtual auto f5() const && -> bool = 0; +}; + +class D : public B { +public: + auto f1() & -> int override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `f1` is not implemented."); + } + + constexpr auto f2() && -> int override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `f2` is not implemented."); + } + + consteval auto f3() -> int override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `f3` is not implemented."); + } + + auto f4() const & -> char override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `f4` is not implemented."); + } + + constexpr auto f5() const && -> bool override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `f5` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +TEST_F(OverridePureVirtualsTests, DefaultParameters) { + ExtraArgs.push_back("-std=c++20"); + + constexpr auto Before = R"cpp( +class B { +public: + virtual void foo(int var = 0) = 0; +}; + +class ^D : public B {}; +)cpp"; + + constexpr auto Expected = R"cpp( +class B { +public: + virtual void foo(int var = 0) = 0; +}; + +class D : public B { +public: + void foo(int var = 0) override { + // TODO: Implement this pure virtual method. + static_assert(false, "Method `foo` is not implemented."); + } +}; +)cpp"; + auto Applied = apply(Before); + EXPECT_EQ(Expected, Applied) << "Applied result:\n" << Applied; +} + +} // namespace +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3ea1c51..2de2818 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -67,6 +67,14 @@ Code completion Code actions ^^^^^^^^^^^^ +- New ``Override pure virtual methods`` code action. When invoked on a class + definition, this action automatically generates C++ ``override`` declarations + for all pure virtual methods inherited from its base classes that have not yet + been implemented. The generated method stubs prompts the user for the actual + implementation. The overrides are intelligently grouped under their original + access specifiers (e.g., ``public``, ``protected``), creating new access + specifier blocks if necessary. + Signature help ^^^^^^^^^^^^^^ @@ -128,6 +136,10 @@ Changes in existing checks - Improved :doc:`misc-header-include-cycle <clang-tidy/checks/misc/header-include-cycle>` check performance. +- Improved :doc:`modernize-use-designated-initializers + <clang-tidy/checks/modernize/use-designated-initializers>` check to + suggest using designated initializers for aliased aggregate types. + - Improved :doc:`modernize-use-std-format <clang-tidy/checks/modernize/use-std-format>` check to correctly match when the format string is converted to a different type by an implicit @@ -142,6 +154,10 @@ Changes in existing checks <clang-tidy/checks/portability/template-virtual-member-function>` check to avoid false positives on pure virtual member functions. +- Improved :doc:`readability-qualified-auto + <clang-tidy/checks/readability/qualified-auto>` check by adding the option + `IgnoreAliasing`, that allows not looking at underlying types of type aliases. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst index efa0857..34390e2 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst @@ -96,3 +96,45 @@ Note in the LLVM alias, the default value is `false`. matched against only the type name (i.e. ``Type``). E.g. to suppress reports for ``std::array`` iterators use `std::array<.*>::(const_)?iterator` string. The default is an empty string. + +.. option:: IgnoreAliasing + + If set to `true` the check will use the underlying type to determine the type + that ``auto`` is deduced to. If set to `false` the check will not look beyond + the first type alias. + Default value is `true`. + + .. code-block:: c++ + + using IntPtr = int*; + IntPtr foo(); + + auto bar = foo(); + + If :option:`IgnoreAliasing` is set to `true`, it will be transformed into: + + .. code-block:: c++ + + auto *bar = foo(); + + Otherwise no changes will occur. + +Limitations +----------- + +When :option:`IgnoreAliasing` is set to `false`, there are cases where +Clang has not preserved the type alias and the underlying type will be used so +false positives may occur. + +For example: + +.. code-block:: c++ + + using IntPtr = int *; + + void loopPtr(const std::vector<IntPtr> &VectorIntPtr) { + + // May fail for IgnoreAliasing==false as AST does not have the 'IntPtr' + for (auto Data : VectorIntPtr) { + } + } diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp index 57e026c..0971a16 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp @@ -69,4 +69,8 @@ void f() { // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] // CHECK-FIXES: mlir::ModuleOp::create(ib) ib.create<mlir::ModuleOp>( ); + + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc()); + mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc()); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp index cdadeed..88e0636 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp @@ -224,3 +224,55 @@ std::array a{1,2,3}; std::array<int,2> b{10, 11}; using array = std::array<int, 2>; array c{10, 11}; + +struct S16 { + int a; + int b; +}; + +using S17 = S16; + +S17 s171{1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S17' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-9]]:1: note: aggregate type is defined here +// CHECK-FIXES: S17 s171{.a=1, .b=2}; +// CHECK-MESSAGES-POD: :[[@LINE-4]]:9: warning: use designated initializer list to initialize 'S17' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: aggregate type is defined here +// CHECK-FIXES-POD: S17 s171{.a=1, .b=2}; + +S17 s172{.a=1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use designated init expression to initialize field 'b' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:16: warning: use designated init expression to initialize field 'b' [modernize-use-designated-initializers] +// CHECK-FIXES: S17 s172{.a=1, .b=2}; + +S17 s173{.a=1, .b=2}; // no issue + +typedef S16 S18; + +S18 s181{1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:9: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] + +S18 s182{1, .b=2}; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-FIXES: S18 s182{.a=1, .b=2}; + +S18 s183{.a=1, .b=2}; // no issue + +struct S19 { + int i; + S17 s17; + S18 s18; +}; + +S19 s191{1, {2, .b=3}, {4, 5}}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S19' [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-8]]:1: note: aggregate type is defined here +// CHECK-MESSAGES: :[[@LINE-3]]:14: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-4]]:24: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-5]]:9: warning: use designated initializer list to initialize 'S19' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: aggregate type is defined here +// CHECK-MESSAGES-POD: :[[@LINE-7]]:14: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-8]]:24: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-FIXES: S19 s191{.i=1, .s17={.a=2, .b=3}, .s18={.a=4, .b=5}}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp index 77afdca..83b7b1d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp @@ -2,6 +2,11 @@ // RUN: -config='{CheckOptions: { \ // RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr" \ // RUN: }}' +// RUN: %check_clang_tidy %s readability-qualified-auto %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr", \ +// RUN: readability-qualified-auto.IgnoreAliasing: false \ +// RUN: }}' -check-suffix=ALIAS -- namespace typedefs { typedef int *MyPtr; @@ -10,22 +15,36 @@ typedef const int *CMyPtr; typedef const int &CMyRef; MyPtr getPtr(); +MyPtr* getPtrPtr(); MyRef getRef(); CMyPtr getCPtr(); +CMyPtr* getCPtrPtr(); CMyRef getCRef(); void foo() { auto TdNakedPtr = getPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedPtr' can be declared as 'auto *TdNakedPtr' // CHECK-FIXES: {{^}} auto *TdNakedPtr = getPtr(); + auto TdNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedPtrPtr' can be declared as 'auto *TdNakedPtrPtr' + // CHECK-FIXES: {{^}} auto *TdNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto TdNakedPtrPtr' can be declared as 'auto *TdNakedPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *TdNakedPtrPtr = getPtrPtr(); auto &TdNakedRef = getRef(); auto TdNakedRefDeref = getRef(); auto TdNakedCPtr = getCPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedCPtr' can be declared as 'const auto *TdNakedCPtr' // CHECK-FIXES: {{^}} const auto *TdNakedCPtr = getCPtr(); + auto TdNakedCPtrPtr = getCPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedCPtrPtr' can be declared as 'auto *TdNakedCPtrPtr' + // CHECK-FIXES: {{^}} auto *TdNakedCPtrPtr = getCPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto TdNakedCPtrPtr' can be declared as 'auto *TdNakedCPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *TdNakedCPtrPtr = getCPtrPtr(); auto &TdNakedCRef = getCRef(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &TdNakedCRef' can be declared as 'const auto &TdNakedCRef' // CHECK-FIXES: {{^}} const auto &TdNakedCRef = getCRef(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &TdNakedCRef' can be declared as 'const auto &TdNakedCRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &TdNakedCRef = getCRef(); auto TdNakedCRefDeref = getCRef(); } @@ -38,6 +57,7 @@ using CMyPtr = const int *; using CMyRef = const int &; MyPtr getPtr(); +MyPtr* getPtrPtr(); MyRef getRef(); CMyPtr getCPtr(); CMyRef getCRef(); @@ -46,6 +66,11 @@ void foo() { auto UNakedPtr = getPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedPtr' can be declared as 'auto *UNakedPtr' // CHECK-FIXES: {{^}} auto *UNakedPtr = getPtr(); + auto UNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedPtrPtr' can be declared as 'auto *UNakedPtrPtr' + // CHECK-FIXES: {{^}} auto *UNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto UNakedPtrPtr' can be declared as 'auto *UNakedPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *UNakedPtrPtr = getPtrPtr(); auto &UNakedRef = getRef(); auto UNakedRefDeref = getRef(); auto UNakedCPtr = getCPtr(); @@ -54,6 +79,8 @@ void foo() { auto &UNakedCRef = getCRef(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &UNakedCRef' can be declared as 'const auto &UNakedCRef' // CHECK-FIXES: {{^}} const auto &UNakedCRef = getCRef(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &UNakedCRef' can be declared as 'const auto &UNakedCRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &UNakedCRef = getCRef(); auto UNakedCRefDeref = getCRef(); } @@ -77,45 +104,67 @@ void foo() { auto NakedPtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto NakedPtr' can be declared as 'auto *NakedPtr' // CHECK-FIXES: {{^}} auto *NakedPtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto NakedPtr' can be declared as 'auto *NakedPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *NakedPtr = getIntPtr(); auto NakedCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto NakedCPtr' can be declared as 'const auto *NakedCPtr' // CHECK-FIXES: {{^}} const auto *NakedCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto NakedCPtr' can be declared as 'const auto *NakedCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *NakedCPtr = getCIntPtr(); const auto ConstPtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstPtr' can be declared as 'auto *const ConstPtr' // CHECK-FIXES: {{^}} auto *const ConstPtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'const auto ConstPtr' can be declared as 'auto *const ConstPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *const ConstPtr = getIntPtr(); const auto ConstCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstCPtr' can be declared as 'const auto *const ConstCPtr' // CHECK-FIXES: {{^}} const auto *const ConstCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'const auto ConstCPtr' can be declared as 'const auto *const ConstCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *const ConstCPtr = getCIntPtr(); volatile auto VolatilePtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatilePtr' can be declared as 'auto *volatile VolatilePtr' // CHECK-FIXES: {{^}} auto *volatile VolatilePtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'volatile auto VolatilePtr' can be declared as 'auto *volatile VolatilePtr' + // CHECK-FIXES-ALIAS: {{^}} auto *volatile VolatilePtr = getIntPtr(); volatile auto VolatileCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatileCPtr' can be declared as 'const auto *volatile VolatileCPtr' // CHECK-FIXES: {{^}} const auto *volatile VolatileCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'volatile auto VolatileCPtr' can be declared as 'const auto *volatile VolatileCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *volatile VolatileCPtr = getCIntPtr(); auto *QualPtr = getIntPtr(); auto *QualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *QualCPtr' can be declared as 'const auto *QualCPtr' // CHECK-FIXES: {{^}} const auto *QualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *QualCPtr' can be declared as 'const auto *QualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *QualCPtr = getCIntPtr(); auto *const ConstantQualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *const ConstantQualCPtr' can be declared as 'const auto *const ConstantQualCPtr' // CHECK-FIXES: {{^}} const auto *const ConstantQualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *const ConstantQualCPtr' can be declared as 'const auto *const ConstantQualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *const ConstantQualCPtr = getCIntPtr(); auto *volatile VolatileQualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *volatile VolatileQualCPtr' can be declared as 'const auto *volatile VolatileQualCPtr' // CHECK-FIXES: {{^}} const auto *volatile VolatileQualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *volatile VolatileQualCPtr' can be declared as 'const auto *volatile VolatileQualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *volatile VolatileQualCPtr = getCIntPtr(); const auto *ConstQualCPtr = getCIntPtr(); auto &Ref = *getIntPtr(); auto &CRef = *getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &CRef' can be declared as 'const auto &CRef' // CHECK-FIXES: {{^}} const auto &CRef = *getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &CRef' can be declared as 'const auto &CRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &CRef = *getCIntPtr(); const auto &ConstCRef = *getCIntPtr(); if (auto X = getCIntPtr()) { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto X' can be declared as 'const auto *X' // CHECK-FIXES: {{^}} if (const auto *X = getCIntPtr()) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:7: warning: 'auto X' can be declared as 'const auto *X' + // CHECK-FIXES-ALIAS: {{^}} if (const auto *X = getCIntPtr()) { } } @@ -153,6 +202,8 @@ void loopRef(std::vector<int> &Mutate, const std::vector<int> &Constant) { for (auto &Data : Constant) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto &Data' can be declared as 'const auto &Data' // CHECK-FIXES: {{^}} for (const auto &Data : Constant) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto &Data' can be declared as 'const auto &Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto &Data : Constant) { observe(Data); } } @@ -161,11 +212,15 @@ void loopPtr(const std::vector<int *> &Mutate, const std::vector<const int *> &C for (auto Data : Mutate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : Mutate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : Mutate) { change(*Data); } for (auto Data : Constant) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : Constant) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : Constant) { observe(*Data); } } @@ -175,12 +230,16 @@ void tempLoopPtr(std::vector<T *> &MutateTemplate, std::vector<const T *> &Const for (auto Data : MutateTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : MutateTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : MutateTemplate) { change(*Data); } //FixMe for (auto Data : ConstantTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : ConstantTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : ConstantTemplate) { observe(*Data); } } @@ -192,12 +251,16 @@ public: for (auto Data : MClassTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : MClassTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:10: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : MClassTemplate) { change(*Data); } //FixMe for (auto Data : CClassTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : CClassTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:10: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : CClassTemplate) { observe(*Data); } } @@ -223,21 +286,31 @@ void baz() { auto MyFunctionPtr = getPtrFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionPtr = getPtrFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionPtr = getPtrFunction(); auto MyFunctionVal = getValFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionVal = getValFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionVal = getValFunction(); auto LambdaTest = [] { return 0; }; // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest' can be declared as 'auto *LambdaTest' // CHECK-FIXES-NOT: {{^}} auto *LambdaTest = [] { return 0; }; + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto LambdaTest' can be declared as 'auto *LambdaTest' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *LambdaTest = [] { return 0; }; auto LambdaTest2 = +[] { return 0; }; // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest2' can be declared as 'auto *LambdaTest2' // CHECK-FIXES-NOT: {{^}} auto *LambdaTest2 = +[] { return 0; }; + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto LambdaTest2' can be declared as 'auto *LambdaTest2' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *LambdaTest2 = +[] { return 0; }; auto MyFunctionRef = *getPtrFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionRef' can be declared as 'auto *MyFunctionRef' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionRef = *getPtrFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto MyFunctionRef' can be declared as 'auto *MyFunctionRef' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionRef = *getPtrFunction(); auto &MyFunctionRef2 = *getPtrFunction(); } @@ -339,10 +412,14 @@ void ignored_types() { auto arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2' // CHECK-FIXES: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2' + // CHECK-FIXES-ALIAS: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); auto not_ignored2 = new std::Ignored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2' // CHECK-FIXES: auto *not_ignored2 = new std::Ignored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2' + // CHECK-FIXES-ALIAS: auto *not_ignored2 = new std::Ignored2(); auto ignored1 = new my::ns::Ignored1(); // CHECK-MESSAGES-NOT: warning: 'auto ignored1' can be declared as 'auto *ignored1' @@ -351,14 +428,20 @@ void ignored_types() { auto not_ignored1 = new my::ns::NotIgnored1(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1' // CHECK-FIXES: auto *not_ignored1 = new my::ns::NotIgnored1(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1' + // CHECK-FIXES-ALIAS: auto *not_ignored1 = new my::ns::NotIgnored1(); auto not2_ignored1 = new my::ns::NotIgnored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1' // CHECK-FIXES: auto *not2_ignored1 = new my::ns::NotIgnored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1' + // CHECK-FIXES-ALIAS: auto *not2_ignored1 = new my::ns::NotIgnored2(); auto not3_ignored1 = new my::Ignored1(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1' // CHECK-FIXES: auto *not3_ignored1 = new my::Ignored1(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1' + // CHECK-FIXES-ALIAS: auto *not3_ignored1 = new my::Ignored1(); } template <typename T> diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp index 725f877..6a9641e 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp @@ -16,5 +16,5 @@ void af2() { void *p = my_malloc(12); my_free(p); free(p); - // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-unix.Malloc] } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp index af9693a..c45f219 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp @@ -7,12 +7,12 @@ void f() { int *p = new int(42); delete p; delete p; - // CHECK: warning: Attempt to free released memory [clang-analyzer-cplusplus.NewDelete] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-cplusplus.NewDelete] } void g() { void *q = malloc(132); free(q); free(q); - // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-unix.Malloc] } |