-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
create new clang-tidy check to add namespaces to symbol references #70621
base: main
Are you sure you want to change the base?
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
} | ||
|
||
std::string getIdentifierString(const IdentifierInfo *identifier) { | ||
return (identifier) ? identifier->getNameStart() : "(nullptr)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are brackets around identifier
necessary?
limitToPattern(Options.get("LimitToPattern", "")), | ||
onlyExpandUsingNamespace(Options.get("OnlyExpandUsingNamespace", true)), | ||
diagnosticLevel(Options.get("DiagnosticLevel", 0)) { | ||
auto limitString = limitToPattern.str(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not use auto
unless type is explicitly spelled in same statement or iterator. Same in other places.
for (; currentTargetIndex < targetContextVector.size(); | ||
++currentTargetIndex) { | ||
auto currentContext = targetContextVector[currentTargetIndex]; | ||
if (auto currentNamespace = dyn_cast<NamespaceDecl>(currentContext)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const auto *
. Same in other places.
readability-use-explicit-namespaces | ||
=================================== | ||
|
||
This check detects and fixes references to members of namespaces where the namespace is not explicity specified in the reference. By default, this will only change references that are found through a using namespace directive. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please synchronize first statement with Release Notes. This check
is omitted. Please follow 80 characters limit. Double space before This check
.
|
||
This check detects and fixes references to members of namespaces where the namespace is not explicity specified in the reference. By default, this will only change references that are found through a using namespace directive. | ||
|
||
Example: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other documentation for code block examples.
string something = "something"; // this is not change by default because it is referenced through using std::string instead of using namespace std | ||
std::cout << something; | ||
|
||
Options: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other documentation for options examples.
// CHECK-MESSAGES: :[[@LINE+1]]:2: warning: Missing namespace qualifiers foo:: | ||
doSomething(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excessive newline.
} | ||
|
||
std::string getIdentifierString(const IdentifierInfo *identifier) { | ||
return (identifier) ? identifier->getNameStart() : "(nullptr)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use getName() and return StringRef instead of std::string
return (identifier) ? identifier->getNameStart() : "(nullptr)"; | ||
} | ||
|
||
std::string getMatchContext(const char *match, const DynTypedNode &node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use StringRef instead of "const char*"
return out.str(); | ||
} | ||
|
||
std::string trueFalseString(bool value) { return value ? "true" : "false"; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return StringRef
|
||
std::string getMatchContext(const char *match, const DynTypedNode &node) { | ||
std::stringstream out; | ||
out << match << "(" << node.getNodeKind().asStringRef().str() << ")"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid std::stringstream, it's expensive to create, just merge those strings, you may use SmallString
UseExplicitNamespacesCheck::UseExplicitNamespacesCheck( | ||
StringRef Name, ClangTidyContext *Context) | ||
: ClangTidyCheck(Name, Context), | ||
limitToPattern(Options.get("LimitToPattern", "")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General: Variables and members should start with Upcase.
@@ -0,0 +1,22 @@ | |||
// RUN: %check_clang_tidy %s readability-use-explicit-namespaces %t | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add tests with:
- templates
- operators
- classes
- fixes
- ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there tools or resources for this? I locally have done a lot more testing, but it is very clear how to turn this into test cases.
Options: | ||
LimitToPattern - only change things that match pattern e.g. "value: std" would limit changes to the std namespace | ||
OnlyExpandUsingNamespace - defaults to true meaning that only references found by using namespace are changed | ||
DiagnosticLevel - add diagnostic information about the choices being made by this check and what it is internally using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This option may not be needed or should be described better,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it may make sense to remove DiagnosticLevel if clang-tidy has a similar concept already - could you identify this?
|
||
IdentifierInfo * | ||
getTypeNestedNameIdentfierRecursive(const Type *type, | ||
std::string &nestedTypeInfo); | ||
bool matchesNamespaceLimits( | ||
const std::vector<const DeclContext *> &targetContextVector); | ||
|
||
void diagOut(const SourceLocation &sourcePosition, | ||
const std::string &message); | ||
|
||
void processTransform(NestedNameSpecifierLoc nestedName, | ||
const SourceLocation &sourcePosition, | ||
const NamedDecl *target, | ||
const DeclContext *referenceContext, bool usingShadow, | ||
const std::string &context); | ||
|
||
void processTypePiecesRecursive(NestedNameSpecifierLoc nestedName, | ||
const TypeLoc &typeLoc, | ||
const DeclContext *declContext, | ||
const std::string &context); | ||
|
||
void processTypePieces(TypeSourceInfo *typeSourceInfo, | ||
const DeclContext *declContext, | ||
const std::string &context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make all those methods private, and if they not needed make them non-class members private methods in .cpp
if (currentNamespace->isAnonymousNamespace()) { | ||
return false; | ||
} | ||
if (currentNamespace->getIdentifier()->getName().str() == name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this may crash, getIdentifier may return nullptr;
return true; | ||
} | ||
size_t currentTargetIndex = 0; | ||
auto findMatch = [¤tTargetIndex, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extract this lambda to separate function
size_t currentTargetIndex = 0; | ||
auto findMatch = [¤tTargetIndex, | ||
&targetContextVector](const std::string &name) -> bool { | ||
while (currentTargetIndex < targetContextVector.size()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use iterators.
while (currentTargetIndex < targetContextVector.size()) { | ||
auto currentContext = targetContextVector[currentTargetIndex]; | ||
++currentTargetIndex; | ||
if (auto currentNamespace = dyn_cast<NamespaceDecl>(currentContext)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (auto currentNamespace = dyn_cast<NamespaceDecl>(currentContext)) { | |
if (const auto* CurrentNamespace = dyn_cast<NamespaceDecl>(currentContext)) { |
if (!currentNamespace->isInline()) { | ||
return false; | ||
} | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduce amount of code blocks, and things like if/else/return
} | ||
return false; | ||
}; | ||
for (size_t i = 0; i < limitToPatternVector.size(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use iterators or range-for
return true; | ||
} | ||
|
||
IdentifierInfo *UseExplicitNamespacesCheck::getTypeNestedNameIdentfierRecursive( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed to make check working, remove custom diagnostic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like an idea, but this check require lot of work.
Todo:
- Update to LLVM codding standard - https://llvm.org/docs/CodingStandards.html
- Remove any custom diagnostic and things (noise) that aren't needed to make check function
- Update code to C++17
- Add more test
- Improve documentation
What should be done when "using namespace" has been abused or used in header files? This check will update all references to include full namespace qualification.
Closes #64441