[clang-tidy] Add redundant qualified alias check (#180404)
Introduce `readability-redundant-qualified-alias` to flag identity type aliases that repeat a qualified name and suggest using-declarations when safe. The check is conservative: it skips macros, elaborated keywords, dependent types, and templates. `OnlyNamespaceScope` controls whether local/class scopes are included (default `false`). Depends on: #183940 #183941
This commit is contained in:
parent
629edaf678
commit
55db533b74
@ -47,6 +47,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
|
||||
RedundantMemberInitCheck.cpp
|
||||
RedundantParenthesesCheck.cpp
|
||||
RedundantPreprocessorCheck.cpp
|
||||
RedundantQualifiedAliasCheck.cpp
|
||||
RedundantSmartptrGetCheck.cpp
|
||||
RedundantStringCStrCheck.cpp
|
||||
RedundantStringInitCheck.cpp
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
#include "RedundantMemberInitCheck.h"
|
||||
#include "RedundantParenthesesCheck.h"
|
||||
#include "RedundantPreprocessorCheck.h"
|
||||
#include "RedundantQualifiedAliasCheck.h"
|
||||
#include "RedundantSmartptrGetCheck.h"
|
||||
#include "RedundantStringCStrCheck.h"
|
||||
#include "RedundantStringInitCheck.h"
|
||||
@ -148,6 +149,8 @@ public:
|
||||
"readability-redundant-parentheses");
|
||||
CheckFactories.registerCheck<RedundantPreprocessorCheck>(
|
||||
"readability-redundant-preprocessor");
|
||||
CheckFactories.registerCheck<RedundantQualifiedAliasCheck>(
|
||||
"readability-redundant-qualified-alias");
|
||||
CheckFactories.registerCheck<RedundantTypenameCheck>(
|
||||
"readability-redundant-typename");
|
||||
CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>(
|
||||
|
||||
@ -0,0 +1,220 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 "RedundantQualifiedAliasCheck.h"
|
||||
#include "../utils/LexerUtils.h"
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::readability {
|
||||
|
||||
namespace {
|
||||
|
||||
struct TypeLocInfo {
|
||||
TypeLoc Loc;
|
||||
bool HasQualifier = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static bool hasMacroInRange(SourceRange Range, const SourceManager &SM,
|
||||
const LangOptions &LangOpts) {
|
||||
if (Range.isInvalid())
|
||||
return true;
|
||||
return utils::lexer::rangeContainsExpansionsOrDirectives(Range, SM, LangOpts);
|
||||
}
|
||||
|
||||
static std::optional<TypeLocInfo> getTypeLocInfo(TypeLoc TL) {
|
||||
if (TL.isNull())
|
||||
return std::nullopt;
|
||||
|
||||
const auto MakeTypeLocInfo = [](auto TypeTL) {
|
||||
const bool HasQualifier =
|
||||
static_cast<bool>(TypeTL.getQualifierLoc().getNestedNameSpecifier());
|
||||
return TypeLocInfo{TypeTL, HasQualifier};
|
||||
};
|
||||
|
||||
if (const auto TypedefTL = TL.getAs<TypedefTypeLoc>())
|
||||
return MakeTypeLocInfo(TypedefTL);
|
||||
|
||||
if (const auto TagTL = TL.getAs<TagTypeLoc>())
|
||||
return MakeTypeLocInfo(TagTL);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static const NamedDecl *getNamedDeclFromTypeLoc(TypeLoc TL) {
|
||||
if (const auto TypedefTL = TL.getAs<TypedefTypeLoc>())
|
||||
return TypedefTL.getDecl();
|
||||
if (const auto TagTL = TL.getAs<TagTypeLoc>())
|
||||
return TagTL.getDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool hasSameUnqualifiedName(const NamedDecl *LHS, const NamedDecl *RHS) {
|
||||
return LHS->getName() == RHS->getName();
|
||||
}
|
||||
|
||||
static bool isNamespaceLikeDeclContext(const DeclContext *DC) {
|
||||
return isa<TranslationUnitDecl, NamespaceDecl>(DC);
|
||||
}
|
||||
|
||||
static bool canUseUsingDeclarationForTarget(const TypeAliasDecl *Alias,
|
||||
const NamedDecl *Target) {
|
||||
const DeclContext *AliasContext = Alias->getDeclContext()->getRedeclContext();
|
||||
const DeclContext *TargetContext =
|
||||
Target->getDeclContext()->getRedeclContext();
|
||||
|
||||
const auto *AliasRecord = dyn_cast<CXXRecordDecl>(AliasContext);
|
||||
if (!AliasRecord)
|
||||
return isNamespaceLikeDeclContext(TargetContext);
|
||||
|
||||
const auto *TargetRecord = dyn_cast<CXXRecordDecl>(TargetContext);
|
||||
return TargetRecord && AliasRecord->isDerivedFrom(TargetRecord);
|
||||
}
|
||||
|
||||
static bool hasTrailingSyntaxAfterRhsType(TypeLoc TL, const SourceManager &SM,
|
||||
const LangOptions &LangOpts) {
|
||||
const SourceLocation TypeEndLoc = TL.getEndLoc();
|
||||
if (TypeEndLoc.isInvalid() || TypeEndLoc.isMacroID())
|
||||
return true;
|
||||
const std::optional<Token> NextToken =
|
||||
utils::lexer::findNextTokenSkippingComments(TypeEndLoc, SM, LangOpts);
|
||||
return !NextToken || NextToken->isNot(tok::semi);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
AST_MATCHER(TypeAliasDecl, isAliasTemplate) {
|
||||
return Node.getDescribedAliasTemplate() != nullptr;
|
||||
}
|
||||
|
||||
AST_MATCHER(NamedDecl, isInMacro) { return Node.getLocation().isMacroID(); }
|
||||
|
||||
AST_MATCHER(TypeAliasDecl, hasAliasAttributes) {
|
||||
if (Node.hasAttrs())
|
||||
return true;
|
||||
const TypeSourceInfo *TSI = Node.getTypeSourceInfo();
|
||||
if (!TSI)
|
||||
return false;
|
||||
for (TypeLoc CurTL = TSI->getTypeLoc(); !CurTL.isNull();
|
||||
CurTL = CurTL.getNextTypeLoc())
|
||||
if (CurTL.getAs<AttributedTypeLoc>())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
AST_MATCHER(TypeLoc, isNonDependentTypeLoc) {
|
||||
return !Node.getType().isNull() && !Node.getType()->isDependentType();
|
||||
}
|
||||
|
||||
AST_MATCHER(TypeLoc, isNonElaboratedTypeLoc) {
|
||||
const auto IsNonElaboratedTypeLoc = [](auto TL) {
|
||||
return !TL.isNull() && !TL.getElaboratedKeywordLoc().isValid();
|
||||
};
|
||||
return IsNonElaboratedTypeLoc(Node.getAs<TypedefTypeLoc>()) ||
|
||||
IsNonElaboratedTypeLoc(Node.getAs<TagTypeLoc>());
|
||||
}
|
||||
|
||||
AST_MATCHER(TypeLoc, isMacroFreeTypeLoc) {
|
||||
const ASTContext &Context = Finder->getASTContext();
|
||||
return !hasMacroInRange(Node.getSourceRange(), Context.getSourceManager(),
|
||||
Context.getLangOpts());
|
||||
}
|
||||
|
||||
AST_MATCHER(TypeLoc, hasNoTrailingSyntaxAfterTypeLoc) {
|
||||
const ASTContext &Context = Finder->getASTContext();
|
||||
return !hasTrailingSyntaxAfterRhsType(Node, Context.getSourceManager(),
|
||||
Context.getLangOpts());
|
||||
}
|
||||
|
||||
AST_MATCHER(TypeAliasDecl, hasUsingDeclarationEquivalentTarget) {
|
||||
const TypeSourceInfo *TSI = Node.getTypeSourceInfo();
|
||||
if (!TSI)
|
||||
return false;
|
||||
const std::optional<TypeLocInfo> TypeInfo = getTypeLocInfo(TSI->getTypeLoc());
|
||||
if (!TypeInfo || !TypeInfo->HasQualifier)
|
||||
return false;
|
||||
const NamedDecl *Target = getNamedDeclFromTypeLoc(TypeInfo->Loc);
|
||||
return Target && hasSameUnqualifiedName(&Node, Target) &&
|
||||
canUseUsingDeclarationForTarget(&Node, Target);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RedundantQualifiedAliasCheck::RedundantQualifiedAliasCheck(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
OnlyNamespaceScope(Options.get("OnlyNamespaceScope", false)) {}
|
||||
|
||||
void RedundantQualifiedAliasCheck::storeOptions(
|
||||
ClangTidyOptions::OptionMap &Opts) {
|
||||
Options.store(Opts, "OnlyNamespaceScope", OnlyNamespaceScope);
|
||||
}
|
||||
|
||||
void RedundantQualifiedAliasCheck::registerMatchers(MatchFinder *Finder) {
|
||||
const auto ControlFlowInitStatementMatcher = stmt(
|
||||
anyOf(mapAnyOf(ifStmt, switchStmt, cxxForRangeStmt)
|
||||
.with(hasInitStatement(stmt(equalsBoundNode("initDeclStmt")))),
|
||||
forStmt(hasLoopInit(stmt(equalsBoundNode("initDeclStmt"))))));
|
||||
|
||||
const auto AliasPreconditions =
|
||||
allOf(unless(isInMacro()), unless(isAliasTemplate()),
|
||||
unless(hasAliasAttributes()));
|
||||
const auto InControlFlowInit =
|
||||
allOf(hasParent(declStmt().bind("initDeclStmt")),
|
||||
hasAncestor(ControlFlowInitStatementMatcher));
|
||||
const auto RewriteableTypeLoc =
|
||||
typeLoc(allOf(isNonDependentTypeLoc(), isNonElaboratedTypeLoc(),
|
||||
isMacroFreeTypeLoc(), hasNoTrailingSyntaxAfterTypeLoc()))
|
||||
.bind("loc");
|
||||
|
||||
const auto RedundantQualifiedAliasMatcher = typeAliasDecl(
|
||||
AliasPreconditions, unless(InControlFlowInit),
|
||||
hasUsingDeclarationEquivalentTarget(), hasTypeLoc(RewriteableTypeLoc));
|
||||
|
||||
if (OnlyNamespaceScope) {
|
||||
Finder->addMatcher(typeAliasDecl(RedundantQualifiedAliasMatcher,
|
||||
hasDeclContext(anyOf(translationUnitDecl(),
|
||||
namespaceDecl())))
|
||||
.bind("alias"),
|
||||
this);
|
||||
return;
|
||||
}
|
||||
Finder->addMatcher(RedundantQualifiedAliasMatcher.bind("alias"), this);
|
||||
}
|
||||
|
||||
void RedundantQualifiedAliasCheck::check(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
const auto *Alias = Result.Nodes.getNodeAs<TypeAliasDecl>("alias");
|
||||
assert(Alias && "matcher must bind alias");
|
||||
const auto *WrittenTLNode = Result.Nodes.getNodeAs<TypeLoc>("loc");
|
||||
assert(WrittenTLNode && "matcher must bind loc");
|
||||
const TypeLoc WrittenTL = *WrittenTLNode;
|
||||
|
||||
const SourceManager &SM = *Result.SourceManager;
|
||||
const LangOptions &LangOpts = getLangOpts();
|
||||
|
||||
const SourceLocation AliasLoc = Alias->getLocation();
|
||||
const SourceLocation RhsBeginLoc = WrittenTL.getBeginLoc();
|
||||
const CharSourceRange EqualRange = utils::lexer::findTokenTextInRange(
|
||||
CharSourceRange::getCharRange(AliasLoc, RhsBeginLoc), SM, LangOpts,
|
||||
[](const Token &Tok) { return Tok.is(tok::equal); });
|
||||
if (EqualRange.isInvalid())
|
||||
return;
|
||||
|
||||
auto Diag = diag(Alias->getLocation(),
|
||||
"type alias is redundant; use a using-declaration instead");
|
||||
|
||||
Diag << FixItHint::CreateRemoval(Alias->getLocation())
|
||||
<< FixItHint::CreateRemoval(EqualRange.getBegin());
|
||||
}
|
||||
|
||||
} // namespace clang::tidy::readability
|
||||
@ -0,0 +1,40 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTQUALIFIEDALIASCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTQUALIFIEDALIASCHECK_H
|
||||
|
||||
#include "../ClangTidyCheck.h"
|
||||
|
||||
namespace clang::tidy::readability {
|
||||
|
||||
/// Finds identity type aliases to qualified names that can be expressed as
|
||||
/// using-declarations.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-qualified-alias.html
|
||||
class RedundantQualifiedAliasCheck : public ClangTidyCheck {
|
||||
public:
|
||||
RedundantQualifiedAliasCheck(StringRef Name, ClangTidyContext *Context);
|
||||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
|
||||
return LangOpts.CPlusPlus11;
|
||||
}
|
||||
std::optional<TraversalKind> getCheckTraversalKind() const override {
|
||||
return TK_IgnoreUnlessSpelledInSource;
|
||||
}
|
||||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
|
||||
private:
|
||||
const bool OnlyNamespaceScope;
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::readability
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTQUALIFIEDALIASCHECK_H
|
||||
@ -154,6 +154,12 @@ New checks
|
||||
Suggests insertion of ``std::move(...)`` to turn copy assignment operator
|
||||
calls into move assignment ones, when deemed valid and profitable.
|
||||
|
||||
- New :doc:`readability-redundant-qualified-alias
|
||||
<clang-tidy/checks/readability/redundant-qualified-alias>` check.
|
||||
|
||||
Finds redundant identity type aliases that re-expose a qualified name and can
|
||||
be replaced with a ``using`` declaration.
|
||||
|
||||
- New :doc:`readability-trailing-comma
|
||||
<clang-tidy/checks/readability/trailing-comma>` check.
|
||||
|
||||
|
||||
@ -417,6 +417,7 @@ Clang-Tidy Checks
|
||||
:doc:`readability-redundant-member-init <readability/redundant-member-init>`, "Yes"
|
||||
:doc:`readability-redundant-parentheses <readability/redundant-parentheses>`, "Yes"
|
||||
:doc:`readability-redundant-preprocessor <readability/redundant-preprocessor>`,
|
||||
:doc:`readability-redundant-qualified-alias <readability/redundant-qualified-alias>`, "Yes"
|
||||
:doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
|
||||
:doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"
|
||||
:doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes"
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
.. title:: clang-tidy - readability-redundant-qualified-alias
|
||||
|
||||
readability-redundant-qualified-alias
|
||||
=====================================
|
||||
|
||||
Finds redundant identity type aliases that re-expose a qualified name and can
|
||||
be replaced with a ``using`` declaration.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
using seconds = std::chrono::seconds;
|
||||
|
||||
// becomes
|
||||
|
||||
using std::chrono::seconds;
|
||||
|
||||
The check is conservative and only warns when the alias name exactly matches
|
||||
the unqualified name of a non-dependent, non-specialized named type written
|
||||
with a qualifier. It skips alias templates, dependent forms, elaborated
|
||||
keywords (``class``, ``struct``, ``enum``, ``typename``), and cases involving
|
||||
macros.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. option:: OnlyNamespaceScope
|
||||
|
||||
When `true`, only consider aliases declared in a namespace or the
|
||||
translation unit. When `false`, also consider aliases declared inside
|
||||
classes, functions, and lambdas. Default is `false`.
|
||||
@ -0,0 +1,203 @@
|
||||
// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-qualified-alias %t
|
||||
// RUN: %check_clang_tidy -check-suffix=NS -std=c++11-or-later %s readability-redundant-qualified-alias %t -- \
|
||||
// RUN: -config='{CheckOptions: { readability-redundant-qualified-alias.OnlyNamespaceScope: true }}'
|
||||
// RUN: %check_clang_tidy -check-suffixes=,CXX23 -std=c++23-or-later %s readability-redundant-qualified-alias %t
|
||||
// RUN: %check_clang_tidy -check-suffixes=NS,NS-CXX23 -std=c++23-or-later %s readability-redundant-qualified-alias %t -- \
|
||||
// RUN: -config='{CheckOptions: { readability-redundant-qualified-alias.OnlyNamespaceScope: true }}'
|
||||
|
||||
namespace n1 {
|
||||
struct Foo {};
|
||||
struct Bar {};
|
||||
struct Attr {};
|
||||
enum PlainEnum { V0 };
|
||||
enum class ScopedEnum { V1 };
|
||||
struct Commented {};
|
||||
struct AfterType {};
|
||||
struct Elab {};
|
||||
struct MacroEq {};
|
||||
struct MacroType {};
|
||||
struct PtrType {};
|
||||
struct LocalType {};
|
||||
} // namespace n1
|
||||
|
||||
namespace n2 {
|
||||
namespace n3 {
|
||||
struct Deep {};
|
||||
} // namespace n3
|
||||
} // namespace n2
|
||||
|
||||
namespace td {
|
||||
typedef n1::Foo TypedefFoo;
|
||||
} // namespace td
|
||||
|
||||
struct GlobalType {};
|
||||
struct Outer {
|
||||
struct Inner {};
|
||||
};
|
||||
|
||||
using Foo = n1::Foo;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead [readability-redundant-qualified-alias]
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead [readability-redundant-qualified-alias]
|
||||
// CHECK-FIXES: using n1::Foo;
|
||||
|
||||
using Bar = ::n1::Bar;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using ::n1::Bar;
|
||||
|
||||
using Attr = n1::Attr __attribute__((aligned(8)));
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
namespace alias_attr {
|
||||
using Foo [[deprecated("alias attr")]] = n1::Foo;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
} // namespace alias_attr
|
||||
|
||||
using Deep = n2::n3::Deep;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using n2::n3::Deep;
|
||||
|
||||
using TypedefFoo = td::TypedefFoo;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using td::TypedefFoo;
|
||||
|
||||
using GlobalType = ::GlobalType;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using ::GlobalType;
|
||||
|
||||
using PlainEnum = n1::PlainEnum;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using n1::PlainEnum;
|
||||
|
||||
using ScopedEnum = n1::ScopedEnum;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using n1::ScopedEnum;
|
||||
|
||||
using Inner = Outer::Inner;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
using Builtin = int;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
using PtrType = n1::PtrType *;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
namespace templ {
|
||||
template <typename T>
|
||||
struct Vec {};
|
||||
} // namespace templ
|
||||
|
||||
using Vec = templ::Vec<int>;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
namespace templ_alias {
|
||||
template <typename T>
|
||||
using Foo = n1::Foo;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
} // namespace templ_alias
|
||||
|
||||
template <typename T>
|
||||
struct Dependent {
|
||||
using X = typename T::X;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
};
|
||||
|
||||
using Elab = class n1::Elab;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
using Commented /*comment*/ = n1::Commented;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using{{[ ]+}}/*comment*/{{[ ]+}}n1::Commented;
|
||||
|
||||
using AfterType = n1::AfterType /*rhs-comment*/;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS: :[[@LINE-2]]:7: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using n1::AfterType /*rhs-comment*/;
|
||||
|
||||
#define DECL_END ;
|
||||
using MacroDeclEnd = n1::MacroType DECL_END
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
#define ALIAS MacroType
|
||||
using ALIAS = n1::MacroType;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
#define RHS n1::MacroType
|
||||
using MacroType = RHS;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
#define EQ =
|
||||
using MacroEq EQ n1::MacroEq;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
struct Base {
|
||||
using T = n1::Foo;
|
||||
};
|
||||
|
||||
struct Derived : Base {
|
||||
using T = Base::T;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using Base::T;
|
||||
};
|
||||
|
||||
struct ClassScopeNamespaceAlias {
|
||||
using Foo = n1::Foo;
|
||||
// CHECK-MESSAGES-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
};
|
||||
|
||||
void local_scope() {
|
||||
using LocalType = n1::LocalType;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-FIXES: using n1::LocalType;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 202302L
|
||||
void cxx23_init_statement_scope(bool Cond) {
|
||||
if (using Foo = n1::Foo; Cond) {
|
||||
}
|
||||
// CHECK-MESSAGES-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
switch (using Bar = ::n1::Bar; 0) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// CHECK-MESSAGES-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
for (using Deep = n2::n3::Deep; Cond;) {
|
||||
Cond = false;
|
||||
}
|
||||
// CHECK-MESSAGES-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
|
||||
int Values[] = {0};
|
||||
for (using GlobalType = ::GlobalType; int V : Values) {
|
||||
(void)V;
|
||||
}
|
||||
// CHECK-MESSAGES-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
// CHECK-MESSAGES-NS-CXX23-NOT: warning: type alias is redundant; use a using-declaration instead
|
||||
}
|
||||
#endif // __cplusplus >= 202302L
|
||||
Loading…
x
Reference in New Issue
Block a user