Index: clang-tidy/fuchsia/AddVisibilityCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/AddVisibilityCheck.h @@ -0,0 +1,43 @@ +//===--- AddVisibilityCheck.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_ADDVISIBILITYCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_ADDVISIBILITYCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Finds functions given a list of names and suggests a fix to add +/// an `__attribute__((visibility("VISIBILITY")))` to their definitions, +/// if they do not already have a visibility attribute. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-add-visibility.html +class AddVisibilityCheck : public ClangTidyCheck { + public: + AddVisibilityCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + private: + void loadNames(); + + std::string VisAttr; + std::vector Names; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_ADDVISIBILITYCHECK_H Index: clang-tidy/fuchsia/AddVisibilityCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/AddVisibilityCheck.cpp @@ -0,0 +1,80 @@ +//===--- AddVisibilityCheck.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 "AddVisibilityCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/Visibility.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER_P(FunctionDecl, hasVisibilityAttr, Visibility, V) { + // if (const auto *D = Node.getDefinition()) { + // return D->getExplicitVisibility(NamedDecl::VisibilityForType) == V; + // } + return Node.getExplicitVisibility(NamedDecl::VisibilityForType) == V; +} + +AddVisibilityCheck::AddVisibilityCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + VisAttr(Options.get("Visibility", "hidden")), + Names(utils::options::parseStringList( + Options.get("Names", "::std::vector"))) {} + +void AddVisibilityCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Names", utils::options::serializeStringList(Names)); + Options.store(Opts, "Visibility", VisAttr); +} + +void AddVisibilityCheck::registerMatchers(MatchFinder *Finder) { + Visibility V; + if (VisAttr == "hidden") + V = HiddenVisibility; + else if (VisAttr == "protected") + V = ProtectedVisibility; + else if (VisAttr == "default") + V = DefaultVisibility; + else + return; + Finder->addMatcher( + functionDecl(allOf(hasAnyName(SmallVector(Names.begin(), + Names.end())), + isDefinition(), unless(hasVisibilityAttr(V)))) + .bind("no-visibility"), + this); +} + +void AddVisibilityCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *D = + Result.Nodes.getNodeAs("no-visibility")) { + const Attr *A = D->getAttr(); + if (A && !A->isInherited() && A->getLocation().isValid()) + diag(D->getLocStart(), + "%0 visibility attribute not set for specified function") + << VisAttr << D + << FixItHint::CreateReplacement(A->getRange(), + "visibility(\"" + VisAttr + "\")"); + else + diag(D->getLocStart(), + "no explicit visibility attribute set for specified function") + << VisAttr << D + << FixItHint::CreateInsertion(D->getLocStart(), + "__attribute__((visibility(\"" + VisAttr + "\")))\n"); + } +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: clang-tidy/fuchsia/CMakeLists.txt =================================================================== --- clang-tidy/fuchsia/CMakeLists.txt +++ clang-tidy/fuchsia/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyFuchsiaModule + AddVisibilityCheck.cpp DefaultArgumentsCheck.cpp FuchsiaTidyModule.cpp MultipleInheritanceCheck.cpp Index: clang-tidy/fuchsia/FuchsiaTidyModule.cpp =================================================================== --- clang-tidy/fuchsia/FuchsiaTidyModule.cpp +++ clang-tidy/fuchsia/FuchsiaTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AddVisibilityCheck.h" #include "DefaultArgumentsCheck.h" #include "MultipleInheritanceCheck.h" #include "OverloadedOperatorCheck.h" @@ -27,6 +28,8 @@ class FuchsiaModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "fuchsia-add-visibility"); CheckFactories.registerCheck( "fuchsia-default-arguments"); CheckFactories.registerCheck( Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -70,6 +70,13 @@ with looping constructs. Every backward jump is rejected. Forward jumps are only allowed in nested loops. +- New `fuchsia-add-visibility + `_ check + + Finds functions given a list of names and suggests a fix to add + an `__attribute__((visibility("VISIBILITY")))` to their definitions, + if they do not already have a visibility attribute. + - New `fuchsia-multiple-inheritance `_ check Index: docs/clang-tidy/checks/fuchsia-add-visibility.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-add-visibility.rst @@ -0,0 +1,34 @@ +.. title:: clang-tidy - fuchsia-add-visibility + +fuchsia-add-visibility +====================== + +Finds functions given a list of names and suggests a fix to add +an `__attribute__((visibility("VISIBILITY")))` to their definitions, +if they do not already have a visibility attribute. + +For example, given the name 'func': + +.. code-block:: c++ + + void func() {} + +would be changed to + +.. code-block:: c++ + + __attribute__((visibility("hidden"))) + void func() {} + +Options +------- + +.. option:: Names + + A string containing a comma-separated list of function names to check for + a visibility attribute. Default is an empty string. + +.. option:: Visibility + + A string specifying what visibility attribute to set, `hidden`, `default`, + or `protected`. Default is `hidden`. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -71,6 +71,7 @@ cppcoreguidelines-pro-type-vararg cppcoreguidelines-slicing cppcoreguidelines-special-member-functions + fuchsia-add-visibility fuchsia-default-arguments fuchsia-multiple-inheritance fuchsia-overloaded-operator Index: test/clang-tidy/fuchsia-add-visibility.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-add-visibility.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy %s fuchsia-add-visibility %t -- \ +// RUN: -config="{CheckOptions: [{key: fuchsia-add-visibility.Names, value: 'foo;bar;baz;foobar'}, \ +// RUN: {key: fuchsia-add-visibility.Visibility, value: 'default'}]}" \ +// RUN: -- -std=c++11 + +#pragma GCC visibility push(hidden) + +void foo(); + +void foo() {} +// CHECK-MESSAGES: [[@LINE-1]]:1: warning: no explicit visibility attribute set for specified function +// CHECK-FIXES: __attribute__((visibility("default"))) + +__attribute__((visibility("default"))) +void bar() {} + +__attribute__((visibility("default"))) +void baz(); + +void baz() {} + +__attribute__((visibility("protected"))) +void foobar() {} +// CHECK-MESSAGES: [[@LINE-2]]:1: warning: default visibility attribute not set for specified function +// CHECK-FIXES: __attribute__((visibility("default")))