juliehockett updated this revision to Diff 135944.
juliehockett marked 6 inline comments as done.
juliehockett added a comment.

After discussion, the goal of this checker slightly changed to target 
definitions in header files, rather than declarations. As a result, the check 
now adds the attribute to any definition (declaration or not) that appears in a 
header file.

Also updating tests.


https://reviews.llvm.org/D43392

Files:
  clang-tidy/fuchsia/AddVisibilityCheck.cpp
  clang-tidy/fuchsia/AddVisibilityCheck.h
  clang-tidy/fuchsia/CMakeLists.txt
  clang-tidy/fuchsia/FuchsiaTidyModule.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/fuchsia-add-visibility.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/fuchsia-add-visibility-pragma.hpp
  test/clang-tidy/fuchsia-add-visibility.cpp
  test/clang-tidy/fuchsia-add-visibility.hpp

Index: test/clang-tidy/fuchsia-add-visibility.hpp
===================================================================
--- /dev/null
+++ test/clang-tidy/fuchsia-add-visibility.hpp
@@ -0,0 +1,48 @@
+// RUN: %check_clang_tidy %s fuchsia-add-visibility %t -- \
+// RUN:   -config="{CheckOptions: [{key: fuchsia-add-visibility.Names, value: 'foo;bar;baz;foobar;f;g;h;i'}, \
+// RUN:								{key: fuchsia-add-visibility.Visibility, value: 'protected'}]}" \
+// RUN:   -header-filter=.* \
+// RUN: -- -std=c++11
+
+void foo();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: no explicit visibility attribute set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+void foo();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: no explicit visibility attribute set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("default")))
+void i();
+// CHECK-MESSAGES: [[@LINE-2]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("default")))
+void i();
+// CHECK-MESSAGES: [[@LINE-2]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("protected")))
+void bar() {}
+
+__attribute__((visibility("protected")))
+void baz();
+void baz() {}
+
+__attribute__((visibility("default")))
+void foobar() {}
+// CHECK-MESSAGES: [[@LINE-2]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("protected"))) 
+void foo(int);
+void foo(double);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: no explicit visibility attribute set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+template <typename Ty>
+__attribute__((visibility("protected"))) 
+void h(Ty);
+
+template <>
+void h<int>(int);
Index: test/clang-tidy/fuchsia-add-visibility.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/fuchsia-add-visibility.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-tidy %s -checks=-*,fuchsia-add-visibility \
+// RUN:   -config="{CheckOptions: [{key: fuchsia-add-visibility.Names, value: 'foo;bar;baz;foobar;f;g'}, \
+// RUN:								{key: fuchsia-add-visibility.Visibility, value: 'protected'}]}" \
+// RUN: -- -std=c++11 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+void foo();
+void foo() {}
Index: test/clang-tidy/fuchsia-add-visibility-pragma.hpp
===================================================================
--- /dev/null
+++ test/clang-tidy/fuchsia-add-visibility-pragma.hpp
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy %s fuchsia-add-visibility %t -- \
+// RUN:   -config="{CheckOptions: [{key: fuchsia-add-visibility.Names, value: 'foo;bar;baz;foobar;f;g'}, \
+// RUN:								{key: fuchsia-add-visibility.Visibility, value: 'protected'}]}" \
+// RUN:   -header-filter=.* \
+// RUN: -- -std=c++11
+
+#pragma GCC visibility push(hidden)
+
+void foo();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("protected")))
+void bar() {}
+
+__attribute__((visibility("protected")))
+void baz();
+void baz() {}
+
+__attribute__((visibility("default")))
+void foobar() {}
+// CHECK-MESSAGES: [[@LINE-2]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+__attribute__((visibility("protected"))) 
+void foo(int);
+void foo(double);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: protected visibility attribute not set for specified function
+// CHECK-FIXES: __attribute__((visibility("protected")))
+
+template <typename Ty>
+__attribute__((visibility("protected"))) 
+void foo(Ty);
+
+template <>
+void foo<int>(int);
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: docs/clang-tidy/checks/fuchsia-add-visibility.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/fuchsia-add-visibility.rst
@@ -0,0 +1,45 @@
+.. 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 header declaration,
+if they do not already have a visibility attribute.
+
+Note: this will apply the fix to all declarations/definitions in header
+files, so please use caution before applying it at large.
+
+For example, given the name 'func' in a header file:
+
+.. 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`.
+
+.. option:: HeaderFileExtensions
+
+   A comma-separated list of filename extensions of header files (the filename
+   extensions should not contain "." prefix). Default is "h".
+   For header files without an extension, use an empty string (if there are no
+   other desired extensions) or leave an empty element in the list. e.g.,
+   "h,hh,hpp,hxx," (note the trailing comma).
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
+  <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-add-visibility.html>`_ 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
   <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html>`_ check
 
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<AddVisibilityCheck>(
+        "fuchsia-add-visibility");
     CheckFactories.registerCheck<DefaultArgumentsCheck>(
         "fuchsia-default-arguments");
     CheckFactories.registerCheck<MultipleInheritanceCheck>(
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/AddVisibilityCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/fuchsia/AddVisibilityCheck.h
@@ -0,0 +1,45 @@
+//===--- 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"
+#include "../utils/HeaderFileExtensionsUtils.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:
+  std::vector<std::string> Names;
+  const std::string VisAttr;
+  Visibility Vis;
+  const std::string RawStringHeaderFileExtensions;
+  utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+}  // 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,98 @@
+//===--- 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) {
+  return Node.getExplicitVisibility(NamedDecl::VisibilityForType) == V;
+}
+
+// AST_MATCHER(FunctionDecl, isInHeaderFile) {
+//   return Node.getExplicitVisibility(NamedDecl::VisibilityForType);
+// }
+
+AddVisibilityCheck::AddVisibilityCheck(StringRef Name,
+                                       ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Names(utils::options::parseStringList(
+          Options.get("Names", "::std::vector"))),
+      VisAttr(Options.get("Visibility", "hidden")),
+      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+  if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+                                        HeaderFileExtensions, ',')) {
+    llvm::errs() << "Invalid header file extension: "
+                 << RawStringHeaderFileExtensions << "\n";
+  }
+  if (VisAttr == "hidden")
+    Vis = HiddenVisibility;
+  else if (VisAttr == "protected")
+    Vis = ProtectedVisibility;
+  else if (VisAttr == "default")
+    Vis = DefaultVisibility;
+  else
+  	llvm::errs() << "Invalid visibliity attribute: " << VisAttr << "\n";
+}
+
+void AddVisibilityCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
+  Options.store(Opts, "Names", utils::options::serializeStringList(Names));
+  Options.store(Opts, "Visibility", VisAttr);
+}
+
+void AddVisibilityCheck::registerMatchers(MatchFinder *Finder) {
+
+  Finder->addMatcher(
+      functionDecl(allOf(hasAnyName(SmallVector<StringRef, 5>(Names.begin(),
+                                                              Names.end())),
+                         unless(hasVisibilityAttr(Vis))))
+          .bind("no-visibility"),
+      this);
+}
+
+void AddVisibilityCheck::check(const MatchFinder::MatchResult &Result) {
+	if (const auto *D = Result.Nodes.getNodeAs<FunctionDecl>("no-visibility")) {
+
+	  // Ignore if it comes from the "main" file ...
+	  if (Result.SourceManager->isInMainFile(
+	          Result.SourceManager->getExpansionLoc(D->getLocStart()))) {
+	    // unless that file is a header.
+	    if (!utils::isSpellingLocInHeaderFile(
+	            D->getLocStart(), *Result.SourceManager, HeaderFileExtensions))
+	      return;
+	  }
+
+		const Attr *A = D->getAttr<VisibilityAttr>();
+		if (A && !A->isInherited() && A->getLocation().isValid())
+			diag(D->getLocStart(),
+	         "%0 visibility attribute not set for specified function.")
+	        << VisAttr
+	        << FixItHint::CreateReplacement(A->getRange(),
+	               "visibility(\"" + VisAttr + "\")");
+		else
+		   diag(D->getLocStart(),
+	         "no explicit visibility attribute set for specified function")
+	        << FixItHint::CreateInsertion(D->getLocStart(),
+	               "__attribute__((visibility(\"" + VisAttr + "\")))\n");
+	}
+}
+
+}  // namespace fuchsia
+}  // namespace tidy
+}  // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to