forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement daedalean-template-specializations check for CS.R.49
- Loading branch information
1 parent
83d3432
commit 22f0b84
Showing
10 changed files
with
398 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
clang-tools-extra/clang-tidy/daedalean/TemplateSpecializationsCheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
//===--- TemplateSpecializationsCheck.cpp - clang-tidy --------------------===// | ||
// | ||
// 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 "TemplateSpecializationsCheck.h" | ||
#include "clang/AST/ASTContext.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
#include "clang/ASTMatchers/ASTMatchers.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace daedalean { | ||
|
||
namespace { | ||
AST_POLYMORPHIC_MATCHER(isDefaultDefinedAndHasSpecializations, | ||
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionTemplateDecl, | ||
ClassTemplateDecl)) { | ||
if (Node.isThisDeclarationADefinition()) { | ||
for (const auto *Specialization : Node.specializations()) { | ||
if (Specialization->isThisDeclarationADefinition()) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
} // namespace | ||
|
||
void TemplateSpecializationsCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher(classTemplateDecl(isDefaultDefinedAndHasSpecializations()) | ||
.bind("class-template-decl"), | ||
this); | ||
|
||
Finder->addMatcher( | ||
functionTemplateDecl(isDefaultDefinedAndHasSpecializations()) | ||
.bind("function-template-decl"), | ||
this); | ||
} | ||
|
||
void TemplateSpecializationsCheck::check( | ||
const MatchFinder::MatchResult &Result) { | ||
|
||
if (const auto *ClassTemplate = | ||
Result.Nodes.getNodeAs<ClassTemplateDecl>("class-template-decl")) { | ||
const auto ClassTemplateDeclLocFile = | ||
Result.SourceManager->getFilename(ClassTemplate->getLocation()); | ||
|
||
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *> | ||
PartialSpecializations; | ||
ClassTemplate->getPartialSpecializations(PartialSpecializations); | ||
|
||
for (const auto *Specialization : PartialSpecializations) { | ||
const auto *Definition = Specialization->getDefinition(); | ||
if (Definition == nullptr) { | ||
return; | ||
} | ||
|
||
const auto ClassTemplateSpecializationLocFile = | ||
Result.SourceManager->getFilename(Definition->getLocation()); | ||
|
||
if (ClassTemplateSpecializationLocFile != ClassTemplateDeclLocFile) { | ||
diag(Definition->getLocation(), | ||
"Partial class template specialization %0 should be defined in " | ||
"the " | ||
"same file as %1") | ||
<< Specialization << ClassTemplate; | ||
} | ||
} | ||
|
||
for (auto *Specialization : ClassTemplate->specializations()) { | ||
const auto *Definition = Specialization->getDefinition(); | ||
if (Definition == nullptr) { | ||
return; | ||
} | ||
|
||
const auto ClassTemplateSpecializationLocFile = | ||
Result.SourceManager->getFilename(Definition->getLocation()); | ||
|
||
if (ClassTemplateSpecializationLocFile != ClassTemplateDeclLocFile) { | ||
diag(Definition->getLocation(), | ||
"Class template specialization %0 should be defined in the " | ||
"same file as %1") | ||
<< Specialization << ClassTemplate; | ||
} | ||
} | ||
} | ||
|
||
if (const auto *FunctionTemplate = | ||
Result.Nodes.getNodeAs<FunctionTemplateDecl>( | ||
"function-template-decl")) { | ||
const auto FunctionTemplateDeclLocFile = | ||
Result.SourceManager->getFilename(FunctionTemplate->getLocation()); | ||
|
||
for (auto *Specialization : FunctionTemplate->specializations()) { | ||
const auto *Definition = Specialization->getDefinition(); | ||
if (Definition == nullptr) { | ||
return; | ||
} | ||
|
||
const auto FunctionTemplateSpecializationLocFile = | ||
Result.SourceManager->getFilename(Definition->getInnerLocStart()); | ||
|
||
if (FunctionTemplateSpecializationLocFile != | ||
FunctionTemplateDeclLocFile) { | ||
diag(Definition->getLocation(), | ||
"Function template specialization %0 should be defined in the " | ||
"same file as %1") | ||
<< Specialization << FunctionTemplate; | ||
|
||
diag(FunctionTemplate->getLocation(), | ||
"Function template first defined here", DiagnosticIDs::Note); | ||
} | ||
} | ||
} | ||
} | ||
|
||
} // namespace daedalean | ||
} // namespace tidy | ||
} // namespace clang |
35 changes: 35 additions & 0 deletions
35
clang-tools-extra/clang-tidy/daedalean/TemplateSpecializationsCheck.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//===--- TemplateSpecializationsCheck.h - clang-tidy ------------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_DAEDALEAN_TEMPLATESPECIALIZATIONSCHECK_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_DAEDALEAN_TEMPLATESPECIALIZATIONSCHECK_H | ||
|
||
#include "../ClangTidyCheck.h" | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace daedalean { | ||
|
||
/// Looks for template specializations for templates with default | ||
/// implementations and checks that they are defined in the same file | ||
/// | ||
/// For the user-facing documentation see: | ||
/// http://clang.llvm.org/extra/clang-tidy/checks/daedalean-template-specializations.html | ||
class TemplateSpecializationsCheck : public ClangTidyCheck { | ||
public: | ||
TemplateSpecializationsCheck(StringRef Name, ClangTidyContext *Context) | ||
: ClangTidyCheck(Name, Context) {} | ||
void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
}; | ||
|
||
} // namespace daedalean | ||
} // namespace tidy | ||
} // namespace clang | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_DAEDALEAN_TEMPLATESPECIALIZATIONSCHECK_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
clang-tools-extra/docs/clang-tidy/checks/daedalean-template-specializations.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.. title:: clang-tidy - daedalean-template-specializations | ||
|
||
daedalean-template-specializations | ||
================================== | ||
|
||
Looks for template specializations for templates with default | ||
implementations and checks that they are defined in the same file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...ools-extra/test/clang-tidy/checkers/Inputs/DDLNHeaders/template-specializations/header.hh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#pragma once | ||
|
||
#include <template-specializations/other-header.hh> | ||
|
||
namespace template_specializations { | ||
|
||
template <typename T> | ||
void justDeclaration(); | ||
|
||
template <typename T> | ||
void function() {} | ||
|
||
template <typename T> | ||
void definedInSource(); | ||
|
||
extern template void definedInSource<float>(); | ||
extern template void definedInSource<int>(); | ||
extern template void definedInSource<double>(); | ||
|
||
template <> | ||
void function<char>() {} | ||
|
||
template <typename T> | ||
class ClassTemplateOnlyDeclared; | ||
|
||
// Partial specialization | ||
template <TriviallyCopyable T> | ||
class ClassTemplateOnlyDeclared<T> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
// Full specialization | ||
template <> | ||
class ClassTemplateOnlyDeclared<int> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <typename T> | ||
class SomeClass { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <> | ||
class SomeClass<char> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <NotTriviallyCopyable T> | ||
class SomeClass<T> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
namespace other_header { | ||
template <> | ||
void function<int>() {} | ||
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: Function template specialization 'function<int>' should be defined in the same file as 'function' [daedalean-template-specializations] | ||
|
||
template <> | ||
class SomeClass<int> { | ||
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: Class template specialization 'SomeClass<int>' should be defined in the same file as 'SomeClass' [daedalean-template-specializations] | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <TriviallyCopyable T> | ||
class SomeClass<T> { | ||
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: Partial class template specialization 'SomeClass<T>' should be defined in the same file as 'SomeClass' [daedalean-template-specializations] | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
} // namespace other_header | ||
|
||
} // namespace template_specializations |
38 changes: 38 additions & 0 deletions
38
...xtra/test/clang-tidy/checkers/Inputs/DDLNHeaders/template-specializations/other-header.hh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#pragma once | ||
|
||
namespace template_specializations { | ||
|
||
template <typename T> | ||
concept TriviallyCopyable = __is_trivially_copyable(T); | ||
|
||
template <typename T> | ||
concept NotTriviallyCopyable = !__is_trivially_copyable(T); | ||
|
||
namespace other_header { | ||
|
||
template <typename T> | ||
void function() {} | ||
|
||
template <> | ||
void function<char>() {} | ||
|
||
template <typename T> | ||
class SomeClass { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <> | ||
class SomeClass<char> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
template <NotTriviallyCopyable T> | ||
class SomeClass<T> { | ||
public: | ||
void doSomething() {} | ||
}; | ||
|
||
} // namespace other_header | ||
} // namespace template_specializations |
Oops, something went wrong.