aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra')
-rw-r--r--clang-tools-extra/clang-doc/JSONGenerator.cpp32
-rw-r--r--clang-tools-extra/clang-doc/Representation.cpp14
-rw-r--r--clang-tools-extra/clang-doc/assets/clang-doc-mustache.css4
-rw-r--r--clang-tools-extra/clang-doc/assets/comment-template.mustache30
-rw-r--r--clang-tools-extra/clang-doc/assets/function-template.mustache4
-rw-r--r--clang-tools-extra/clang-tidy/llvm/CMakeLists.txt2
-rw-r--r--clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp16
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp34
-rw-r--r--clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h1
-rw-r--r--clang-tools-extra/clangd/FindSymbols.cpp12
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt3
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/OverridePureVirtuals.cpp374
-rw-r--r--clang-tools-extra/clangd/unittests/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp5
-rw-r--r--clang-tools-extra/clangd/unittests/tweaks/OverridePureVirtualsTests.cpp720
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst16
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst42
-rw-r--r--clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h4
-rw-r--r--clang-tools-extra/test/clang-doc/basic-project.mustache.test271
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp4
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp52
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp83
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp2
-rw-r--r--clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp4
26 files changed, 1700 insertions, 45 deletions
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 92a4117..599b381 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -103,6 +103,18 @@ static json::Value extractTextComments(Object *ParagraphComment) {
return *ParagraphComment->get("Children");
}
+static json::Value extractVerbatimComments(json::Array VerbatimLines) {
+ json::Value TextArray = json::Array();
+ auto &TextArrayRef = *TextArray.getAsArray();
+ for (auto &Line : VerbatimLines)
+ TextArrayRef.push_back(*Line.getAsObject()
+ ->get("VerbatimBlockLineComment")
+ ->getAsObject()
+ ->get("Text"));
+
+ return TextArray;
+}
+
static Object serializeComment(const CommentInfo &I, Object &Description) {
// taken from PR #142273
Object Obj = Object();
@@ -126,6 +138,8 @@ static Object serializeComment(const CommentInfo &I, Object &Description) {
auto TextCommentsArray = extractTextComments(CARef.front().getAsObject());
if (I.Name == "brief")
insertComment(Description, TextCommentsArray, "BriefComments");
+ else if (I.Name == "return")
+ insertComment(Description, TextCommentsArray, "ReturnComments");
return Obj;
}
@@ -147,19 +161,19 @@ static Object serializeComment(const CommentInfo &I, Object &Description) {
Child.insert({"ParamName", I.ParamName});
Child.insert({"Direction", I.Direction});
Child.insert({"Explicit", I.Explicit});
- Child.insert({"Children", ChildArr});
- Obj.insert({commentKindToString(I.Kind), ChildVal});
+ auto TextCommentsArray = extractTextComments(CARef.front().getAsObject());
+ Child.insert({"Children", TextCommentsArray});
+ if (I.Kind == CommentKind::CK_ParamCommandComment)
+ insertComment(Description, ChildVal, "ParamComments");
return Obj;
}
case CommentKind::CK_VerbatimBlockComment: {
- Child.insert({"Text", I.Text});
- if (!I.CloseName.empty())
- Child.insert({"CloseName", I.CloseName});
- Child.insert({"Children", ChildArr});
- if (I.CloseName == "endcode")
- insertComment(Description, ChildVal, "CodeComments");
- else if (I.CloseName == "endverbatim")
+ if (I.CloseName == "endcode") {
+ // We don't support \code language specification
+ auto TextCommentsArray = extractVerbatimComments(CARef);
+ insertComment(Description, TextCommentsArray, "CodeComments");
+ } else if (I.CloseName == "endverbatim")
insertComment(Description, ChildVal, "VerbatimComments");
return Obj;
}
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-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
index a885a36..e555ee7 100644
--- a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
+++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css
@@ -469,3 +469,7 @@ a, a:visited, a:hover, a:active {
text-decoration: none;
color: inherit;
}
+
+.code-block {
+ white-space: pre-line;
+}
diff --git a/clang-tools-extra/clang-doc/assets/comment-template.mustache b/clang-tools-extra/clang-doc/assets/comment-template.mustache
index f2edb1b..4e38e5f 100644
--- a/clang-tools-extra/clang-doc/assets/comment-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/comment-template.mustache
@@ -24,6 +24,36 @@
{{>Comments}}
{{/Children}}
{{/ParagraphComment}}
+{{#HasParamComments}}
+ <h3>Parameters</h3>
+ {{#ParamComments}}
+ <div>
+ <b>{{ParamName}}</b> {{#Explicit}}{{Direction}}{{/Explicit}} {{#Children}}{{>Comments}}{{/Children}}
+ </div>
+ {{/ParamComments}}
+{{/HasParamComments}}
+{{#HasReturnComments}}
+ <h3>Returns</h3>
+ {{#ReturnComments}}
+ {{#.}}
+ <p>{{TextComment}}</p>
+ {{/.}}
+ {{/ReturnComments}}
+{{/HasReturnComments}}
+{{#HasCodeComments}}
+ <h3>Code</h3>
+ {{#CodeComments}}
+ <div>
+ <pre class="code-block">
+ <code>
+ {{#.}}
+ {{.}}
+ {{/.}}
+ </code>
+ </pre>
+ </div>
+ {{/CodeComments}}
+{{/HasCodeComments}}
{{#BlockCommandComment}}
<div class="block-command-comment__command">
<div class="block-command-command">
diff --git a/clang-tools-extra/clang-doc/assets/function-template.mustache b/clang-tools-extra/clang-doc/assets/function-template.mustache
index 6683afa..2510a4d 100644
--- a/clang-tools-extra/clang-doc/assets/function-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/function-template.mustache
@@ -14,10 +14,10 @@
</code>
</pre>
{{! Function Comments }}
- {{#FunctionComments}}
+ {{#Description}}
<div>
{{>Comments}}
</div>
- {{/FunctionComments}}
+ {{/Description}}
</div>
</div>
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/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp
index 84bcbc1..7655a39 100644
--- a/clang-tools-extra/clangd/FindSymbols.cpp
+++ b/clang-tools-extra/clangd/FindSymbols.cpp
@@ -14,6 +14,7 @@
#include "SourceCode.h"
#include "index/Index.h"
#include "support/Logger.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Index/IndexSymbol.h"
#include "llvm/ADT/ArrayRef.h"
@@ -391,6 +392,17 @@ private:
D = TD;
}
+ // FriendDecls don't act as DeclContexts, but they might wrap a function
+ // definition that won't be visible through other means in the AST. Hence
+ // unwrap it here instead.
+ if (auto *Friend = llvm::dyn_cast<FriendDecl>(D)) {
+ if (auto *Func =
+ llvm::dyn_cast_or_null<FunctionDecl>(Friend->getFriendDecl())) {
+ if (Func->isThisDeclarationADefinition())
+ D = Func;
+ }
+ }
+
VisitKind Visit = shouldVisit(D);
if (Visit == VisitKind::No)
return;
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/FindSymbolsTests.cpp b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
index 282859c..5b1630e 100644
--- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
@@ -335,6 +335,7 @@ TEST(DocumentSymbols, BasicSymbols) {
Foo(int a) {}
void $decl[[f]]();
friend void f1();
+ friend void f2() {}
friend class Friend;
Foo& operator=(const Foo&);
~Foo();
@@ -346,7 +347,7 @@ TEST(DocumentSymbols, BasicSymbols) {
};
void f1();
- inline void f2() {}
+ void f2();
static const int KInt = 2;
const char* kStr = "123";
@@ -386,6 +387,8 @@ TEST(DocumentSymbols, BasicSymbols) {
withDetail("(int)"), children()),
AllOf(withName("f"), withKind(SymbolKind::Method),
withDetail("void ()"), children()),
+ AllOf(withName("f2"), withKind(SymbolKind::Function),
+ withDetail("void ()"), children()),
AllOf(withName("operator="), withKind(SymbolKind::Method),
withDetail("Foo &(const Foo &)"), children()),
AllOf(withName("~Foo"), withKind(SymbolKind::Constructor),
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-doc/Inputs/basic-project/include/Circle.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h
index 7bee3ff..74bffcd 100644
--- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h
+++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h
@@ -26,6 +26,10 @@ public:
/**
* @brief Calculates the perimeter of the circle.
*
+ * @code
+ * Circle circle(5.0);
+ * double perimeter = circle.perimeter();
+ * @endcode
* @return double The perimeter of the circle.
*/
double perimeter() const override;
diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
index 4fb38e2..e2d9da6 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
@@ -83,6 +83,19 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc">
HTML-SHAPE: double area ()
HTML-SHAPE: </code>
HTML-SHAPE: </pre>
+HTML-SHAPE: <div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p> Calculates the area of the shape.</p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p></p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p></p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <h3>Returns</h3>
+HTML-SHAPE: <p> double The area of the shape.</p>
+HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: <div class="delimiter-container">
@@ -92,6 +105,19 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc">
HTML-SHAPE: double perimeter ()
HTML-SHAPE: </code>
HTML-SHAPE: </pre>
+HTML-SHAPE: <div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p> Calculates the perimeter of the shape.</p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p></p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p></p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <h3>Returns</h3>
+HTML-SHAPE: <p> double The perimeter of the shape.</p>
+HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: <div class="delimiter-container">
@@ -101,6 +127,14 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc">
HTML-SHAPE: void ~Shape ()
HTML-SHAPE: </code>
HTML-SHAPE: </pre>
+HTML-SHAPE: <div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p> Virtual destructor.</p>
+HTML-SHAPE: </div>
+HTML-SHAPE: <div>
+HTML-SHAPE: <p></p>
+HTML-SHAPE: </div>
+HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: </div>
HTML-SHAPE: </div>
@@ -220,6 +254,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc">
HTML-CALC: int add (int a, int b)
HTML-CALC: </code>
HTML-CALC: </pre>
+HTML-CALC: <div>
+HTML-CALC: <div>
+HTML-CALC: <p> Adds two integers.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <h3>Parameters</h3>
+HTML-CALC: <div>
+HTML-CALC: <b>a</b> <div>
+HTML-CALC: <p> First integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <b>b</b> <div>
+HTML-CALC: <p> Second integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <h3>Returns</h3>
+HTML-CALC: <p> int The sum of a and b.</p>
+HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: <div class="delimiter-container">
@@ -229,6 +293,19 @@ HTML-CALC: <code class="language-cpp code-clang-doc">
HTML-CALC: int subtract (int a, int b)
HTML-CALC: </code>
HTML-CALC: </pre>
+HTML-CALC: <div>
+HTML-CALC: <div>
+HTML-CALC: <p> Subtracts the second integer from the first.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <h3>Returns</h3>
+HTML-CALC: <p> int The result of a - b.</p>
+HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: <div class="delimiter-container">
@@ -238,6 +315,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc">
HTML-CALC: int multiply (int a, int b)
HTML-CALC: </code>
HTML-CALC: </pre>
+HTML-CALC: <div>
+HTML-CALC: <div>
+HTML-CALC: <p> Multiplies two integers.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <h3>Parameters</h3>
+HTML-CALC: <div>
+HTML-CALC: <b>a</b> <div>
+HTML-CALC: <p> First integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <b>b</b> <div>
+HTML-CALC: <p> Second integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <h3>Returns</h3>
+HTML-CALC: <p> int The product of a and b.</p>
+HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: <div class="delimiter-container">
@@ -247,6 +354,37 @@ HTML-CALC: <code class="language-cpp code-clang-doc">
HTML-CALC: double divide (int a, int b)
HTML-CALC: </code>
HTML-CALC: </pre>
+HTML-CALC: <div>
+HTML-CALC: <div>
+HTML-CALC: <p> Divides the first integer by the second.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <h3>Parameters</h3>
+HTML-CALC: <div>
+HTML-CALC: <b>a</b> <div>
+HTML-CALC: <p> First integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <b>b</b> <div>
+HTML-CALC: <p> Second integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <h3>Returns</h3>
+HTML-CALC: <p> double The result of a / b.</p>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: <div class="delimiter-container">
@@ -256,6 +394,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc">
HTML-CALC: int mod (int a, int b)
HTML-CALC: </code>
HTML-CALC: </pre>
+HTML-CALC: <div>
+HTML-CALC: <div>
+HTML-CALC: <p> Performs the mod operation on integers.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: <h3>Parameters</h3>
+HTML-CALC: <div>
+HTML-CALC: <b>a</b> <div>
+HTML-CALC: <p> First integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <b>b</b> <div>
+HTML-CALC: <p> Second integer.</p>
+HTML-CALC: </div>
+HTML-CALC: <div>
+HTML-CALC: <p></p>
+HTML-CALC: </div>
+HTML-CALC: </div>
+HTML-CALC: <h3>Returns</h3>
+HTML-CALC: <p> The result of a % b.</p>
+HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
HTML-CALC: </div>
@@ -344,6 +512,31 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc">
HTML-RECTANGLE: void Rectangle (double width, double height)
HTML-RECTANGLE: </code>
HTML-RECTANGLE: </pre>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p> Constructs a new Rectangle object.</p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <h3>Parameters</h3>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <b>width</b> <div>
+HTML-RECTANGLE: <p> Width of the rectangle.</p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <b>height</b> <div>
+HTML-RECTANGLE: <p> Height of the rectangle.</p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: <div class="delimiter-container">
@@ -353,6 +546,19 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc">
HTML-RECTANGLE: double area ()
HTML-RECTANGLE: </code>
HTML-RECTANGLE: </pre>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p> Calculates the area of the rectangle.</p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <h3>Returns</h3>
+HTML-RECTANGLE: <p> double The area of the rectangle.</p>
+HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: <div class="delimiter-container">
@@ -362,6 +568,19 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc">
HTML-RECTANGLE: double perimeter ()
HTML-RECTANGLE: </code>
HTML-RECTANGLE: </pre>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p> Calculates the perimeter of the rectangle.</p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <div>
+HTML-RECTANGLE: <p></p>
+HTML-RECTANGLE: </div>
+HTML-RECTANGLE: <h3>Returns</h3>
+HTML-RECTANGLE: <p> double The perimeter of the rectangle.</p>
+HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
HTML-RECTANGLE: </div>
@@ -450,6 +669,23 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc">
HTML-CIRCLE: void Circle (double radius)
HTML-CIRCLE: </code>
HTML-CIRCLE: </pre>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p> Constructs a new Circle object.</p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <h3>Parameters</h3>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <b>radius</b> <div>
+HTML-CIRCLE: <p> Radius of the circle.</p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: <div class="delimiter-container">
@@ -459,6 +695,19 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc">
HTML-CIRCLE: double area ()
HTML-CIRCLE: </code>
HTML-CIRCLE: </pre>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p> Calculates the area of the circle.</p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <h3>Returns</h3>
+HTML-CIRCLE: <p> double The area of the circle.</p>
+HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: <div class="delimiter-container">
@@ -468,6 +717,28 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc">
HTML-CIRCLE: double perimeter ()
HTML-CIRCLE: </code>
HTML-CIRCLE: </pre>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p> Calculates the perimeter of the circle.</p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <p></p>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: <h3>Returns</h3>
+HTML-CIRCLE: <p> double The perimeter of the circle.</p>
+HTML-CIRCLE: <h3>Code</h3>
+HTML-CIRCLE: <div>
+HTML-CIRCLE: <pre class="code-block">
+HTML-CIRCLE: <code>
+HTML-CIRCLE: Circle circle(5.0);
+HTML-CIRCLE: double perimeter = circle.perimeter();
+HTML-CIRCLE: </code>
+HTML-CIRCLE: </pre>
+HTML-CIRCLE: </div>
+HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
HTML-CIRCLE: </div>
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]
}