Index: clang-tidy/cert/AvoidReservedNamesCheck.h =================================================================== --- /dev/null +++ clang-tidy/cert/AvoidReservedNamesCheck.h @@ -0,0 +1,40 @@ +//===--- AvoidReservedNamesCheck.h - clang-tidy------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_AVOID_RESERVED_NAMES_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_AVOID_RESERVED_NAMES_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace cert { + +/// This check will catch names declared or defined as a reserved identifier. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cert-dcl51-cpp.html +class AvoidReservedNamesCheck : public ClangTidyCheck { +public: + AvoidReservedNamesCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void declNameIsReservedCheck(StringRef Name, SourceLocation Location, bool IsGlobal); + void macroNameIsKeywordCheck(const Token &MacroNameTok); + void registerPPCallbacks(CompilerInstance &Compiler) override; +private: + bool isInGlobalNamespace(const Decl *D); +}; + +} // namespace cert +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_AVOID_RESERVED_NAMES_H Index: clang-tidy/cert/AvoidReservedNamesCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/cert/AvoidReservedNamesCheck.cpp @@ -0,0 +1,213 @@ +//===--- AvoidReservedNamesCheck.cpp - clang-tidy--------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AvoidReservedNamesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include +#include + +using namespace clang::ast_matchers; + +namespace { +std::array Keywords = {"override", + "final", + "noreturn", + "carries_dependency", + "deprecated", + "fallthrough", + "nodiscard", + "maybe_unused", + "optimize_for_synchronized", + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "const", + "constexpr", + "const_cast", + "continue", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq"}; +} // namespace + +namespace clang { +namespace tidy { +namespace cert { + +namespace { +class AvoidReservedNamesPPCallbacks : public PPCallbacks { +public: + AvoidReservedNamesPPCallbacks(Preprocessor *PP, + AvoidReservedNamesCheck *Check) + : PP(PP), Check(Check) {} + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + macroNameCheck(MacroNameTok); + } + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) override { + macroNameCheck(MacroNameTok); + } + +private: + Preprocessor *PP; + AvoidReservedNamesCheck *Check; + void macroNameCheck(const Token &MacroNameTok) { + if (!MacroNameTok.getLocation().isValid() || + PP->getSourceManager().isInSystemHeader(MacroNameTok.getLocation())) + return; + Check->macroNameIsKeywordCheck(MacroNameTok); + Check->declNameIsReservedCheck(MacroNameTok.getIdentifierInfo()->getName(), + MacroNameTok.getLocation(), true); + } +}; +} // namespace + +void AvoidReservedNamesCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(namedDecl().bind("var"), this); + Finder->addMatcher(labelStmt().bind("label"), this); +} + +void AvoidReservedNamesCheck::check(const MatchFinder::MatchResult &Result) { + const auto *ND = Result.Nodes.getNodeAs("var"); + + if (const auto *L = Result.Nodes.getNodeAs("label")) + ND = L->getDecl(); + + if (!ND->getLocation().isValid() || + Result.SourceManager->isInSystemHeader(ND->getLocation()) || + !ND->getIdentifier()) + return; + + declNameIsReservedCheck(ND->getName(), ND->getLocation(), + isInGlobalNamespace(ND)); +} + +void AvoidReservedNamesCheck::declNameIsReservedCheck(StringRef Name, + SourceLocation Location, + bool IsGlobal) { + + if (Name.find("__") != StringRef::npos) + diag(Location, "do not use names that contain a double underscore"); + if (IsGlobal && Name.startswith("_")) + diag(Location, "do not use global names that start with an underscore"); + if (Name.startswith("_") && Name.size() > 1 && std::isupper(Name[1])) + diag(Location, "do not use names that begin with an " + "underscore followed by an uppercase " + "letter"); +} + +bool AvoidReservedNamesCheck::isInGlobalNamespace(const Decl *D) { + if (D->getDeclContext()->isTranslationUnit()) + return true; + if (auto NS = dyn_cast(D->getDeclContext())) { + if (!NS->isAnonymousNamespace()) + return false; + return isInGlobalNamespace(NS); + } + return false; +} + +void AvoidReservedNamesCheck::macroNameIsKeywordCheck( + const Token &MacroNameTok) { + if (Keywords.end() != std::find(Keywords.begin(), Keywords.end(), + MacroNameTok.getIdentifierInfo()->getName())) + diag(MacroNameTok.getLocation(), "do not use macro names which are " + "identical to keywords or attribute " + "tokens"); +} + +void AvoidReservedNamesCheck::registerPPCallbacks(CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique( + &Compiler.getPreprocessor(), this)); +} + +} // namespace cert +} // namespace tidy +} // namespace clang Index: clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tidy/cert/CERTTidyModule.cpp +++ clang-tidy/cert/CERTTidyModule.cpp @@ -16,6 +16,7 @@ #include "../misc/NonCopyableObjects.h" #include "../misc/StaticAssertCheck.h" #include "../misc/ThrowByValueCatchByReferenceCheck.h" +#include "AvoidReservedNamesCheck.h" #include "CommandProcessorCheck.h" #include "DontModifyStdNamespaceCheck.h" #include "FloatLoopCounter.h" @@ -39,6 +40,8 @@ CheckFactories.registerCheck( "cert-dcl21-cpp"); CheckFactories.registerCheck("cert-dcl50-cpp"); + CheckFactories.registerCheck( + "cert-dcl51-cpp"); CheckFactories.registerCheck( "cert-dcl54-cpp"); CheckFactories.registerCheck( Index: clang-tidy/cert/CMakeLists.txt =================================================================== --- clang-tidy/cert/CMakeLists.txt +++ clang-tidy/cert/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyCERTModule + AvoidReservedNamesCheck.cpp CERTTidyModule.cpp CommandProcessorCheck.cpp DontModifyStdNamespaceCheck.cpp Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -62,6 +62,11 @@ Checks if the overloaded postfix ``operator++/--`` returns a constant object. +- New `cert-dcl51-cpp + `_ check + + Checks if a name is declared or defined with a reserved identifier. + - New `cert-dcl58-cpp `_ check Index: docs/clang-tidy/checks/cert-dcl51-cpp.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/cert-dcl51-cpp.rst @@ -0,0 +1,39 @@ +.. title:: clang-tidy - cert-dcl51-cpp + +cert-dcl51-cpp +============== + +This check will catch the following errors due to these are +names declared or defined as a reserved identifier: + - Names in the global namespace should not start with an underscore. + - Names should not start with an underscore followed by an uppercase letter. + - Names should not contain a double underscore. + - Names defined in macros should not be identical to keywords. + +Here's an example using variables: + +.. code-block:: c++ + + #define override + // warning: macro name should not be identical to keyword + + int _global_variable; + // warning: global name starts with an underscore + + void function() { + int loval__variable; + // warning: name contains a double underscore + + int _Uppercase_variable; + // warning: name starts with an underscore followed by an uppercase letter + } + +This check does not include warnings for reserved macro names and +user defined literals, since checks have already been written to those: +- Wreserved-id-macro +- Wuser-defined-literals + +This check corresponds to the CERT C++ Coding Standard rule +`DCL51-CPP. Do not declare or define a reserved identifier +`_. + Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -8,6 +8,7 @@ cert-dcl03-c (redirects to misc-static-assert) cert-dcl21-cpp cert-dcl50-cpp + cert-dcl51-cpps cert-dcl54-cpp (redirects to misc-new-delete-overloads) cert-dcl58-cpp cert-dcl59-cpp (redirects to google-build-namespaces) Index: test/clang-tidy/Inputs/Headers/sha.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/Headers/sha.h @@ -0,0 +1,6 @@ +#pragma clang system_header + +namespace std { + #define override __override__ + int __variable__; +} Index: test/clang-tidy/cert-avoid-reserved-names.cpp =================================================================== --- /dev/null +++ test/clang-tidy/cert-avoid-reserved-names.cpp @@ -0,0 +1,136 @@ +// RUN: %check_clang_tidy %s cert-dcl51-cpp %t -- -- -I %S/Inputs/Headers + +#include "sha.h" + +#define _MACRO_NAME_ +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +#define override +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use macro names which are identical to keywords or attribute tokens [cert-dcl51-cpp] +#define else__if +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use names that contain a double underscore [cert-dcl51-cpp] + +int _global_variable; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +int _Upper; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +int __variable; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: do not use names that contain a double underscore [cert-dcl51-cpp] +int some__variable; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use names that contain a double underscore [cert-dcl51-cpp] +void fun__ction() { + int local__variable; +} +// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: do not use names that contain a double underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-3]]:7: warning: do not use names that contain a double underscore [cert-dcl51-cpp] +void _Function() { + int _Case; +} +// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-4]]:7: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] + +typedef int _Integer; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] + +using _Char = char; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] + +template void _fun__ction(); +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-2]]:28: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-3]]:28: warning: do not use names that contain a double underscore [cert-dcl51-cpp] + +enum _global_names { + _Variable = 1, + second__variable = 2 +}; +// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: do not use names that contain a double underscore [cert-dcl51-cpp] + +void __Function() { + _label__: + if (true) { + goto _label__; + } +} +// CHECK-MESSAGES: :[[@LINE-6]]:6: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-7]]:6: warning: do not use names that contain a double underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-7]]:3: warning: do not use names that contain a double underscore [cert-dcl51-cpp] + +namespace _reserved_namespace_ { + int _Variable; + struct _Struct_name { + void Fun__ction(); + }; +} +// CHECK-MESSAGES: :[[@LINE-6]]:11: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-6]]:7: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: do not use names that contain a double underscore [cert-dcl51-cpp] + +namespace { + int _variable; + class _Classname { + void _Function(); + }; + namespace { + int _still_global; + } +} +// CHECK-MESSAGES: :[[@LINE-8]]:7: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-8]]:9: warning: do not use global names that start with an underscore [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-9]]:10: warning: do not use names that begin with an underscore followed by an uppercase letter [cert-dcl51-cpp] +// CHECK-MESSAGES: :[[@LINE-7]]:9: warning: do not use global names that start with an underscore [cert-dcl51-cpp] + + +// Something that doesn't trigger the check: +#define MACRO_NAME +#define override2 +#define else_if + +int some_variable; + +void fun_ction() { + int _local_lower_variable; +} + +typedef int Integer; +using Char = char; + +template void function(); + +enum my_enum { + variable = 1, + other_variable = 2 +}; + +void Function() { + _label_: + if (true) { + goto _label_; + } +} + +namespace my_space { + int _variable; + struct _struct_name_ { + void _function(); + }; + namespace { + int _my_variable; + } +} + +namespace { + class Classname { + void _my_function(); + }; + bool operator==(Classname a, double b); +}