Index: clang-tidy/CMakeLists.txt =================================================================== --- clang-tidy/CMakeLists.txt +++ clang-tidy/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(bugprone) add_subdirectory(cert) add_subdirectory(cppcoreguidelines) +add_subdirectory(fuchsia) add_subdirectory(google) add_subdirectory(hicpp) add_subdirectory(llvm) Index: clang-tidy/fuchsia/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tidy/fuchsia/CMakeLists.txt @@ -0,0 +1,20 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangTidyFuchsiaModule + DefaultArgumentsCheck.cpp + FuchsiaTidyModule.cpp + MultipleInheritanceCheck.cpp + OverloadedOperatorCheck.cpp + StaticallyConstructedObjectsCheck.cpp + ThreadLocalCheck.cpp + TrailingReturnCheck.cpp + VirtualInheritanceCheck.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangLex + clangTidy + clangTidyUtils + ) Index: clang-tidy/fuchsia/DefaultArgumentsCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/DefaultArgumentsCheck.h @@ -0,0 +1,35 @@ +//===--- DefaultArgumentsCheck.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_FUCHSIA_DEFAULT_ARGUMENTS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_DEFAULT_ARGUMENTS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Default arguments are not allowed in declared or called functions. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-default-arguments.html +class DefaultArgumentsCheck : public ClangTidyCheck { +public: + DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_DEFAULT_ARGUMENTS_H Index: clang-tidy/fuchsia/DefaultArgumentsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/DefaultArgumentsCheck.cpp @@ -0,0 +1,42 @@ +//===--- DefaultArgumentsCheck.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 "DefaultArgumentsCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER(ParmVarDecl, hasDefaultArgument) { return Node.hasDefaultArg(); } + +void DefaultArgumentsCheck::registerMatchers(MatchFinder *Finder) { + // Calling a function which uses default arguments is disallowed. + Finder->addMatcher(cxxDefaultArgExpr().bind("stmt"), this); + // Declaring default parameters is disallowed. + Finder->addMatcher(parmVarDecl(hasDefaultArgument()).bind("decl"), this); +} + +void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) { + if (const CXXDefaultArgExpr *S = + Result.Nodes.getNodeAs("stmt")) { + diag(S->getUsedLocation(), + "calling functions which use default arguments is disallowed"); + diag(S->getParam()->getLocStart(), "the default parameter was declared here", + DiagnosticIDs::Note); + } else if (const ParmVarDecl *D = Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(), + "declaring functions which use default arguments is disallowed"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/FuchsiaTidyModule.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/FuchsiaTidyModule.cpp @@ -0,0 +1,59 @@ +//===--- FuchsiaTidyModule.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 "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "DefaultArgumentsCheck.h" +#include "MultipleInheritanceCheck.h" +#include "OverloadedOperatorCheck.h" +#include "StaticallyConstructedObjectsCheck.h" +#include "ThreadLocalCheck.h" +#include "TrailingReturnCheck.h" +#include "VirtualInheritanceCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// This module is for Fuchsia specific checks. +class FuchsiaModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + + CheckFactories.registerCheck( + "fuchsia-default-arguments"); + CheckFactories.registerCheck( + "fuchsia-multiple-inheritance"); + CheckFactories.registerCheck( + "fuchsia-overloaded-operator"); + CheckFactories.registerCheck( + "fuchsia-statically-constructed-objects"); + CheckFactories.registerCheck( + "fuchsia-thread-local"); + CheckFactories.registerCheck( + "fuchsia-trailing-return"); + CheckFactories.registerCheck( + "fuchsia-virtual-inheritance"); + } +}; +// Register the FuchsiaTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add + X("fuchsia-module", "Adds Fuchsia platform checks."); + +} // namespace fuchsia + +// This anchor is used to force the linker to link in the generated object file +// and thus register the FuchsiaModule. +volatile int FuchsiaModuleAnchorSource = 0; + +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/MultipleInheritanceCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/MultipleInheritanceCheck.h @@ -0,0 +1,51 @@ +//===--- MultipleInheritanceCheck.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_FUCHSIA_MULTIPLE_INHERITANCE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Mulitple inheritance is disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html +class MultipleInheritanceCheck : public ClangTidyCheck { +public: + MultipleInheritanceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + void onStartOfTranslationUnit() override { + InterfaceMap = new llvm::StringMap; + } + void onEndOfTranslationUnit() override { delete InterfaceMap; } + + void addNodeToInterfaceMap(const CXXRecordDecl *Node, bool isInterface); + bool getInterfaceStatus(const CXXRecordDecl *Node, bool *isInterface); + bool isCurrentClassInterface(const CXXRecordDecl *Node); + bool isInterface(const CXXRecordDecl *Node); + +private: + // Contains the identity of each named CXXRecord as an interface. This is used + // to memoize lookup speeds and improve performance from O(N^2) to O(N), where N + // is the number of classes. + llvm::StringMap *InterfaceMap; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H Index: clang-tidy/fuchsia/MultipleInheritanceCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/MultipleInheritanceCheck.cpp @@ -0,0 +1,121 @@ +//===--- MultipleInheritanceCheck.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 "MultipleInheritanceCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang; +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + + AST_MATCHER(CXXRecordDecl, hasDefinition) { + if (!Node.hasDefinition()) + return false; + return true; + } + +// Adds a node (by name) to the interface map, if it was not present in the map +// previously. +void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node, + bool isInterface) { + StringRef Name = Node->getIdentifier()->getName(); + MultipleInheritanceCheck::InterfaceMap->insert( + std::make_pair(Name, isInterface)); +} + +// Returns "true" if the boolean "isInterface" has been set to the +// interface status of the current Node. Return "false" if the +// interface status for the current node is not yet known. +bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node, + bool *isInterface) { + StringRef Name = Node->getIdentifier()->getName(); + if (MultipleInheritanceCheck::InterfaceMap->count(Name)) { + *isInterface = MultipleInheritanceCheck::InterfaceMap->lookup(Name); + return true; + } + return false; +} + +// TODO(smklein): Make an exception for 'Dispatcher' -- consider it an +// interface, even though it isn't. +bool MultipleInheritanceCheck::isCurrentClassInterface( + const CXXRecordDecl *Node) { + // Interfaces should have no fields. + if (!Node->field_empty()) { + return false; + } + // Interfaces should have exclusively pure methods. + for (auto method : Node->methods()) { + if (method->isUserProvided() && !method->isPure()) { + return false; + } + } + return true; +} + +bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) { + // Short circuit the lookup if we have analyzed this record before. + bool PreviousIsInterfaceResult; + if (MultipleInheritanceCheck::getInterfaceStatus(Node, + &PreviousIsInterfaceResult)) { + return PreviousIsInterfaceResult; + } + + // To be an interface, all base classes must be interfaces as well. + for (const auto &I : Node->bases()) { + const RecordType *Ty = I.getType()->getAs(); + assert(Ty && "RecordType of base class is unknown"); + CXXRecordDecl *Base = cast(Ty->getDecl()->getDefinition()); + if (!MultipleInheritanceCheck::isInterface(Base)) { + MultipleInheritanceCheck::addNodeToInterfaceMap(Node, false); + return false; + } + } + + bool CurrentClassIsInterface = + MultipleInheritanceCheck::isCurrentClassInterface(Node); + MultipleInheritanceCheck::addNodeToInterfaceMap(Node, + CurrentClassIsInterface); + return CurrentClassIsInterface; +} + +void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) { + // Match declarations which have definitions. + Finder->addMatcher(cxxRecordDecl(hasDefinition()).bind("decl"), this); +} + +void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) { + if (const CXXRecordDecl *D = + Result.Nodes.getNodeAs("decl")) { + + // Check against map to see if if the class inherits from multiple + // concrete classes + int NumConcrete = 0; + for (const auto &I : D->bases()) { + const RecordType *Ty = I.getType()->getAs(); + assert(Ty && "RecordType of base class is unknown"); + CXXRecordDecl *Base = cast(Ty->getDecl()->getDefinition()); + if (!MultipleInheritanceCheck::isInterface(Base)) + NumConcrete++; + } + + if (NumConcrete > 1) { + diag(D->getLocStart(), "inheriting mulitple classes which aren't " + "pure virtual is disallowed"); + } + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/OverloadedOperatorCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/OverloadedOperatorCheck.h @@ -0,0 +1,35 @@ +//===--- OverloadedOperatorCheck.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_FUCHSIA_OVERLOADED_OPERATOR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_OVERLOADED_OPERATOR_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Operator overloading is disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-overloaded-operator.html +class OverloadedOperatorCheck : public ClangTidyCheck { +public: + OverloadedOperatorCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_OVERLOADED_OPERATOR_H Index: clang-tidy/fuchsia/OverloadedOperatorCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/OverloadedOperatorCheck.cpp @@ -0,0 +1,38 @@ +//===--- OverloadedOperatorCheck.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 "OverloadedOperatorCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER(CXXMethodDecl, hasOverloadedOperator) { + if (Node.isCopyAssignmentOperator() || Node.isMoveAssignmentOperator()) { + return false; + } + return Node.isOverloadedOperator(); +} + +void OverloadedOperatorCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(cxxMethodDecl(hasOverloadedOperator()).bind("decl"), this); +} + +void OverloadedOperatorCheck::check(const MatchFinder::MatchResult &Result) { + if (const CXXMethodDecl *D = + Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(),"operator overloading is disallowed"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.h @@ -0,0 +1,35 @@ +//===--- StaticallyConstructedObjectsCheck.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_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Constructing objects which are statically stored is disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html +class StaticallyConstructedObjectsCheck : public ClangTidyCheck { +public: + StaticallyConstructedObjectsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H Index: clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp @@ -0,0 +1,42 @@ +//===--- StaticallyConstructedObjectsCheck.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 "StaticallyConstructedObjectsCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) { + // Constructing objects which are stored statically is disallowed. + Finder->addMatcher( + varDecl(allOf( + // Match statically stored objects... + hasStaticStorageDuration(), + // ... which have C++ constructors... + hasDescendant(cxxConstructExpr(unless( + // ... that are not constexpr. + hasDeclaration(cxxConstructorDecl(isConstexpr()))))))) + .bind("decl"), + this); +} + +void StaticallyConstructedObjectsCheck::check(const MatchFinder::MatchResult &Result) { + if (const VarDecl *D = Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(), "statically constructed objects are disallowed"); + diag(D->getLocStart(), "if possible, use a constexpr constructor instead", + DiagnosticIDs::Note); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/ThreadLocalCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/ThreadLocalCheck.h @@ -0,0 +1,35 @@ +//===--- ThreadLocalCheck.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_FUCHSIA_THREAD_LOCAL_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_THREAD_LOCAL_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Thread-local storage is disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-thread-local.html +class ThreadLocalCheck : public ClangTidyCheck { +public: + ThreadLocalCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_THREAD_LOCAL_H Index: clang-tidy/fuchsia/ThreadLocalCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/ThreadLocalCheck.cpp @@ -0,0 +1,33 @@ +//===--- ThreadLocalCheck.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 "ThreadLocalCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +void ThreadLocalCheck::registerMatchers(MatchFinder *Finder) { + // Using thread-local storage is disallowed. + Finder->addMatcher(varDecl(hasThreadStorageDuration()).bind("decl"), this); +} + +void ThreadLocalCheck::check(const MatchFinder::MatchResult &Result) { + if (const VarDecl *D = Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(), "thread local storage is disallowed"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/TrailingReturnCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/TrailingReturnCheck.h @@ -0,0 +1,35 @@ +//===--- TrailingReturnCheck.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_FUCHSIA_TRAILING_RETURN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_TRAILING_RETURN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Functions with trailing returns are disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-trailing-return.html +class TrailingReturnCheck : public ClangTidyCheck { +public: + TrailingReturnCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_TRAILING_RETURN_H Index: clang-tidy/fuchsia/TrailingReturnCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/TrailingReturnCheck.cpp @@ -0,0 +1,39 @@ +//===--- TrailingReturnCheck.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 "TrailingReturnCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER(FunctionDecl, hasTrailingReturn) { + const Type *T = Node.getType().getTypePtr(); + const FunctionProtoType *F = cast(T); + return F->hasTrailingReturn(); +} + +void TrailingReturnCheck::registerMatchers(MatchFinder *Finder) { + // Functions which have trailing returns are disallowed. + Finder->addMatcher(functionDecl(hasTrailingReturn()).bind("decl"), this); +} + +void TrailingReturnCheck::check(const MatchFinder::MatchResult &Result) { + if (const Decl *D = Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(), "trailing returns are disallowed"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/VirtualInheritanceCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/VirtualInheritanceCheck.h @@ -0,0 +1,35 @@ +//===--- VirtualInheritanceCheck.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_FUCHSIA_VIRTUAL_INHERITANCE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_VIRTUAL_INHERITANCE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Defining classes with virtual inheritance is disallowed. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-virtual-inheritance.html +class VirtualInheritanceCheck : public ClangTidyCheck { +public: + VirtualInheritanceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_VIRTUAL_INHERITANCE_H Index: clang-tidy/fuchsia/VirtualInheritanceCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/VirtualInheritanceCheck.cpp @@ -0,0 +1,54 @@ +//===--- VirtualInheritanceCheck.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 "VirtualInheritanceCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER(CXXRecordDecl, hasVirtualBaseClass) { + return Node.hasDefinition() && (Node.getNumVBases() != 0); +} + +void VirtualInheritanceCheck::registerMatchers(MatchFinder *Finder) { + // Defining classes using virtual inheritance is disallowed. + Finder->addMatcher(cxxRecordDecl(hasVirtualBaseClass()).bind("decl"), this); + // Calling constructors of classes using virtual inheritance is disallowed. + // To clarify, this matcher finds, in order: + // 1) Calls to Constructors, + // 2) The declarations of those constructors, + // 3) The classes those constructors belong to, + // 4) And matches the classes which have virtual base classes. + Finder->addMatcher( + cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + ofClass(cxxRecordDecl(hasVirtualBaseClass()))))) + .bind("stmt"), + this); +} + +void VirtualInheritanceCheck::check(const MatchFinder::MatchResult &Result) { + if (const CXXRecordDecl *D = + Result.Nodes.getNodeAs("decl")) { + diag(D->getLocStart(), "[kernel-c++] virtual inheritance is disallowed"); + } else if (const CXXConstructExpr *S = + Result.Nodes.getNodeAs("stmt")) { + diag(S->getLocStart(), + "[kernel-c++] constructing a class which inherits " + "a virtual base class is disallowed"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/tool/CMakeLists.txt =================================================================== --- clang-tidy/tool/CMakeLists.txt +++ clang-tidy/tool/CMakeLists.txt @@ -21,6 +21,7 @@ clangTidyBugproneModule clangTidyCERTModule clangTidyCppCoreGuidelinesModule + clangTidyFuchsiaModule clangTidyGoogleModule clangTidyHICPPModule clangTidyLLVMModule Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -482,6 +482,11 @@ static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination = CppCoreGuidelinesModuleAnchorSource; +// This anchor is used to force the linker to link the GoogleModule. +extern volatile int FuchsiaModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED FuchsiaModuleAnchorDestination = + FuchsiaModuleAnchorSource; + // This anchor is used to force the linker to link the GoogleModule. extern volatile int GoogleModuleAnchorSource; static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination = Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,41 @@ Improvements to clang-tidy -------------------------- +- New `fuchsia-multiple-inheritance + `_ check + + Check to prevent multiple inheritance in Fuchsia. + +- New `fuchsia-virtual-inheritance + `_ check + + Check to prevent the definition of classes with virtual inheritance. + +- New `fuchsia-trailing-return + `_ check + + Check to prevent functions with trailing returns in Fuchsia. + +- New `fuchsia-thread-local + `_ check + + Check to prevent thread-local storage in Fuchsia. + +- New `fuchsia-statically-constructed-objects + `_ check + + Check to prevent creation of statically-stored objects in Fuchsia. + +- New `fuchsia-overloaded-operator + `_ check + + Check to prevent operator overloading in Fuchsia. + +- New `fuchsia-default-arguments + `_ check + + Check to prevent use of default arguments in declared or called functions in Fuchsia. + - New `objc-property-declaration `_ check @@ -67,8 +102,8 @@ - New `google-objc-global-variable-declaration `_ check - Add new check for Objective-C code to ensure global - variables follow the naming convention of 'k[A-Z].*' (for constants) + Add new check for Objective-C code to ensure global + variables follow the naming convention of 'k[A-Z].*' (for constants) or 'g[A-Z].*' (for variables). - New module `objc` for Objective-C style checks. @@ -137,7 +172,7 @@ Finds cases where integer division in a floating point context is likely to cause unintended loss of precision. -- New `cppcoreguidelines-owning-memory `_ check +- New `cppcoreguidelines-owning-memory `_ check This check implements the type-based semantic of ``gsl::owner``, but without flow analysis. @@ -145,13 +180,13 @@ - New `hicpp-exception-baseclass `_ check - Ensures that all exception will be instances of ``std::exception`` and classes + Ensures that all exception will be instances of ``std::exception`` and classes that are derived from it. - New `hicpp-signed-bitwise `_ check - Finds uses of bitwise operations on signed integer types, which may lead to + Finds uses of bitwise operations on signed integer types, which may lead to undefined or implementation defined behaviour. - New `android-cloexec-inotify-init1 @@ -170,7 +205,7 @@ `_ option. -- Added aliases for the `High Integrity C++ Coding Standard `_ +- Added aliases for the `High Integrity C++ Coding Standard `_ to already implemented checks in other modules. - `hicpp-deprecated-headers `_ Index: docs/clang-tidy/checks/fuchsia-default-arguments.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-default-arguments.rst @@ -0,0 +1,24 @@ +.. title:: clang-tidy - fuchsia-default-arguments + +fuchsia-default-arguments +========================= + +Warns if a function is declared or called with default arguments. + +Ex. The declaration: + +.. code-block:: c++ + + int foo(int value = 5) { return value; } + +will cause a warning. + +If a function with default arguments is already defined, calling it with no +arguments will also cause a warning. Calling it without defaults will not cause +a warning: +.. code-block:: c++ + + foo(); // warning + foo(0); // no warning + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst @@ -0,0 +1,46 @@ +.. title:: clang-tidy - fuchsia-multiple-inheritance + +fuchsia-multiple-inheritance +============================ + +Warns if a function inherits from multiple classes that are not pure virtual. + +Ex: Declaring a class that inherits from multiple concrete classes is +disallowed: + +.. code-block:: c++ + + class Base_A { + public: + virtual int foo() { return 0; } + }; + + class Base_B { + public: + virtual int bar() { return 0; } + }; + + // Warning + class Bad_Child1 : public Base_A, Base_B {}; + +A class that inherits from a pure virtual is allowed: + +.. code-block:: c++ + + class Interface_A { + public: + virtual int foo() = 0; + }; + + class Interface_B { + public: + virtual int bar() = 0; + }; + + // No warning + class Good_Child1 : public Interface_A, Interface_B { + virtual int foo() override { return 0; } + virtual int bar() override { return 0; } + }; + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-overloaded-operator.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-overloaded-operator.rst @@ -0,0 +1,17 @@ +.. title:: clang-tidy - fuchsia-overloaded-operator + +fuchsia-overloaded-operator +=========================== + +Warns if an operator is overloaded, except for the copy and move operators. + +Ex. + +.. code-block:: c++ + + int operator+(int); // Warning + + B &operator=(B other); // No warning + B &operator=(B &&other) // No warning + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-statically-constructed-objects.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-statically-constructed-objects.rst @@ -0,0 +1,32 @@ +.. title:: clang-tidy - fuchsia-statically-constructed-objects + +fuchsia-statically-constructed-objects +====================================== + +Warns if statically-stored objects are created, unless constructed +with constexpr. + +Ex. Creating static classes or structs is not allowed: + +.. code-block:: c++ + + class AdderClass { + public: + AdderClass(int value1, int value2) : val(value1 + value2) {} + constexpr AdderClass(int value) : val(value) {} + + private: + int val; + }; + + // Will cause warning + static AdderClass a(1, 2); + +But creation of static objects using constexpr constructors is allowed: + +.. code-block:: c++ + + // No warning + static AdderClass b(0); + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-thread-local.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-thread-local.rst @@ -0,0 +1,15 @@ +.. title:: clang-tidy - fuchsia-thread-local + +fuchsia-thread-local +==================== + +Warns if thread-local storage is used. + +Ex. Using thread_local or extern thread_local is not allowed: + +.. code-block:: c++ + + thread_local int foo; // Warning + extern thread_local int bar; // Warning + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-trailing-return.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-trailing-return.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - fuchsia-trailing-return + +fuchsia-trailing-return +======================= + +Warns if a function has a trailing return. + +Ex. + +.. code-block:: c++ + + // No warning + int add_one(const int arg) { return arg; } + + // Warning + auto get_add_one() -> int (*)(const int) { + return add_one; + } + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/fuchsia-virtual-inheritance.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-virtual-inheritance.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - fuchsia-virtual-inheritance + +fuchsia-virtual-inheritance +=========================== + +Warns if classes are defined or created with virtual inheritance. + +Ex. Classes should not be defined with virtual inheritance: + +.. code-block:: c++ + + class B : public virtual A {} // warning + +Classes with virtual inheritance should not be created: + +.. code-block:: c++ + + B *b = new B(); // warning + +See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -54,6 +54,13 @@ cppcoreguidelines-pro-type-vararg cppcoreguidelines-slicing cppcoreguidelines-special-member-functions + fuchsia-default-arguments + fuchsia-multiple-inheritance + fuchsia-overloaded-operator + fuchsia-statically-constructed-objects + fuchsia-thread-local + fuchsia-trailing-return + fuchsia-virtual-inheritance google-build-explicit-make-pair google-build-namespaces google-build-using-namespace Index: test/clang-tidy/fuchsia-default-arguments.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-default-arguments.cpp @@ -0,0 +1,19 @@ +// RUN: %check_clang_tidy %s fuchsia-default-arguments %t + +int foo(int value = 5) { return value; } +// CHECK-MESSAGES: [[@LINE-1]]:9: warning: declaring functions which use default arguments is disallowed [fuchsia-default-arguments] + +int f(void) { + foo(); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling functions which use default arguments is disallowed [fuchsia-default-arguments] + // CHECK-NEXT: note: the default parameter was declared here: + // CHECK-NEXT: int foo(int value = 5) { return value; } +} + +// Negatives. +int bar(int value) { return value; } + +int n(void) { + foo(0); + bar(0); +} Index: test/clang-tidy/fuchsia-multiple-inheritance.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-multiple-inheritance.cpp @@ -0,0 +1,91 @@ +// RUN: %check_clang_tidy %s fuchsia-multiple-inheritance %t + +class Base_A { +public: + virtual int foo() { return 0; } +}; + +class Base_B { +public: + virtual int bar() { return 0; } +}; + +class Base_A_child : public Base_A { +public: + virtual int baz() { return 0; } +}; + +class Interface_A { +public: + virtual int foo() = 0; +}; + +class Interface_B { +public: + virtual int bar() = 0; +}; + +class Interface_C { +public: + virtual int blat() = 0; +}; + +class Interface_A_with_member { +public: + virtual int foo() = 0; + int val = 0; +}; + +class Interface_with_A_Parent : public Base_A { +public: + virtual int baz() = 0; +}; + +// Inherits from multiple concrete classes. +// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes which aren't pure virtual is disallowed [fuchsia-multiple-inheritance] +// CHECK-NEXT: class Bad_Child1 : public Base_A, Base_B {}; +class Bad_Child1 : public Base_A, Base_B {}; + +// CHECK-MESSAGES: [[@LINE+1]]:1: warning: inheriting mulitple classes which aren't pure virtual is disallowed [fuchsia-multiple-inheritance] +class Bad_Child2 : public Base_A, Interface_A_with_member { + virtual int foo() override { return 0; } +}; + +// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes which aren't pure virtual is disallowed [fuchsia-multiple-inheritance] +// CHECK-NEXT: class Bad_Child3 : public Interface_with_A_Parent, Base_B { +class Bad_Child3 : public Interface_with_A_Parent, Base_B { + virtual int baz() override { return 0; } +}; + +// Easy cases of single inheritance +class Simple_Child1 : public Base_A {}; +class Simple_Child2 : public Interface_A { + virtual int foo() override { return 0; } +}; + +// Valid uses of multiple inheritance +class Good_Child1 : public Interface_A, Interface_B { + virtual int foo() override { return 0; } + virtual int bar() override { return 0; } +}; + +class Good_Child2 : public Base_A, Interface_B { + virtual int bar() override { return 0; } +}; + +class Good_Child3 : public Base_A_child, Interface_C, Interface_B { + virtual int bar() override { return 0; } + virtual int blat() override { return 0; } +}; + +int main(void) { + Bad_Child1 a; + Bad_Child2 b; + Bad_Child3 c; + Simple_Child1 d; + Simple_Child2 e; + Good_Child1 f; + Good_Child2 g; + Good_Child3 h; + return 0; +} Index: test/clang-tidy/fuchsia-overloaded-operator.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-overloaded-operator.cpp @@ -0,0 +1,15 @@ +// RUN: %check_clang_tidy %s fuchsia-overloaded-operator %t + +class A { +public: + int operator+(int); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: operator overloading is disallowed [fuchsia-overloaded-operator] +}; + +class B { +public: + B &operator=(B other); + // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: operator overloading is disallowed [fuchsia-overloaded-operator] + B &operator=(B &&other); + // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: operator overloading is disallowed [fuchsia-overloaded-operator] +}; Index: test/clang-tidy/fuchsia-statically-constructed-objects.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-statically-constructed-objects.cpp @@ -0,0 +1,46 @@ +// RUN: %check_clang_tidy %s fuchsia-statically-constructed-objects %t + +class AdderClass { +public: + AdderClass(int value1, int value2) : val(value1 + value2) {} + constexpr AdderClass(int value) : val(value) {} + +private: + int val; +}; + +struct mystruct { + int a; +}; + +struct mystruct_with_method { + int a; + void b() { a++; } +}; + +struct static_mystruct_container { + int a; + static int b; + static struct mystruct c; +}; + +int main(void) { + + static AdderClass a(1, 2); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: statically constructed objects are disallowed + // CHECK-NEXT: static AdderClass a(1, 2); + + // Allowed (constexpr ctor) + static AdderClass b(0); + + static struct mystruct c; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: statically constructed objects are disallowed + // CHECK-NEXT: static struct mystruct c; + + static struct mystruct_with_method d; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: statically constructed objects are disallowed + // CHECK-NEXT: static struct mystruct_with_method d; + + static int e; + struct static_mystruct_container f; +} Index: test/clang-tidy/fuchsia-thread-local.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-thread-local.cpp @@ -0,0 +1,13 @@ +// RUN: %check_clang_tidy %s fuchsia-thread-local %t + +int main(void) { + thread_local int foo; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: thread local storage is disallowed + // CHECK-NEXT: thread_local int foo; + + extern thread_local int bar; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: thread local storage is disallowed + // CHECK-NEXT: extern thread_local int bar; + int baz; + return 0; +} Index: test/clang-tidy/fuchsia-trailing-return.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-trailing-return.cpp @@ -0,0 +1,14 @@ +// RUN: %check_clang_tidy %s fuchsia-trailing-return %t + +int add_one(const int arg) { return arg; } + +auto get_add_one() -> int (*)(const int) { + // CHECK-MESSAGES: [[@LINE-1]]:1: warning: trailing returns are disallowed + // CHECK-NEXT: auto get_add_one() -> int (*)(const int) { + return add_one; +} + +int main(void) { + get_add_one()(5); + return 0; +} Index: test/clang-tidy/fuchsia-virtual-inheritance.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-virtual-inheritance.cpp @@ -0,0 +1,54 @@ +// RUN: %check_clang_tidy %s fuchsia-virtual-inheritance %t + +class A { +public: + A(int value) : val(value) {} + + int do_A() { return val; } + +private: + int val; +}; + +class B : public virtual A { + // CHECK-MESSAGES: [[@LINE-1]]:1: warning: [kernel-c++] virtual inheritance is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: class B : public virtual A { +public: + B() : A(0) {} + int do_B() { return 1 + do_A(); } +}; + +class C : public virtual A { + // CHECK-MESSAGES: [[@LINE-1]]:1: warning: [kernel-c++] virtual inheritance is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: class C : public virtual A { +public: + C() : A(0) {} + int do_C() { return 2 + do_A(); } +}; + +class D : public B, public C { + // CHECK-MESSAGES: [[@LINE-1]]:1: warning: [kernel-c++] virtual inheritance is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: class C : public B, public C { +public: + D(int value) : A(value), B(), C() {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: [kernel-c++] constructing a class which inherits a virtual base class is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: D(int value) : A(value), B(), C() {} + // CHECK-MESSAGES: [[@LINE-3]]:33: warning: [kernel-c++] constructing a class which inherits a virtual base class is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: D(int value) : A(value), B(), C() {} + + int do_D() { return do_A() + do_B() + do_C(); } +}; + +int main(void) { + A *a = new A(0); + B *b = new B(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: [kernel-c++] constructing a class which inherits a virtual base class is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: B *b = new B(); + C *c = new C(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: [kernel-c++] constructing a class which inherits a virtual base class is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: C *c = new C(); + D *d = new D(0); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: [kernel-c++] constructing a class which inherits a virtual base class is disallowed [fuchsia-virtual-inheritance] + // CHECK-NEXT: D *d = new D(0); + return 0; +}