cjdb updated this revision to Diff 364555.
cjdb marked 10 inline comments as done.
cjdb added a comment.

- adds TODOs
- adds asserts
- removes "imported" SourceManager (apparently there was already a pointer in 
`Result`)
- fixes C++ documentation to match opening line of RST doc


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107294/new/

https://reviews.llvm.org/D107294

Files:
  clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp
  clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h
  clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp
  clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c
  clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c
  clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp
  clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
===================================================================
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/readability/BUILD.gn
@@ -12,6 +12,7 @@
     "//llvm/lib/Support",
   ]
   sources = [
+    "AlternativeTokensCheck.cpp",
     "AvoidConstParamsInDecls.cpp",
     "BracesAroundStatementsCheck.cpp",
     "ConstReturnTypeCheck.cpp",
Index: clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/diagnostics/readability-strict-const-correctness.cpp
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidm1 %s readabilitm1-strict-const-correctness %t
+int f1()
+{
+  int c1 = 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c1' is never modified and can be const-qualified
+  // CHECK-FIXES: int const c1 = 0;
+
+  int m1 = c1;
+  m1 += 5;
+
+  int ca[] = {0, 1};
+  m1 = a[0];
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'ca' elements are never modified and can be const-qualified
+  // CHECK-FIXES: int const ca[] = {0, 1};
+
+  int ma[] = {0, 1};
+  ma[0] = 10;
+
+  int& clr = m1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'r1' never modifies its referee and can be const-qualified
+  // CHECK-FIXES: int const& r1 = m1;
+
+  int m2 = c1;
+  int& r2 = m2;
+  r2 = m1;
+
+  int&& rr = 5; // No warning
+
+  int const* c2 = &m1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c2' is never modified and can be const-qualified
+  // CHECK-FIXES: int const* const c2 = &m1;
+
+  int* const c3 = &m1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c3' never modifies its pointee and can be const-qualified
+  // CHECK-FIXES: int const* const c3 = &m1;
+
+  int* c4 = &m1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c4' is never modified and can be const-qualified
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'c4' never modifies its pointee and can be const-qualified
+  // CHECK-FIXES: int const* const c4 = &m1;
+
+  int* pointer_const = &m1;
+  *pointer_const = m2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'pointer_const' is never modified and can be const-qualified
+  // CHECK-FIXES: int* const pointer_const = &m1;
+
+  int* pointee_const = ma;
+  ++pointee_const;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: 'pointee_const' never modifies its pointee and can be const-qualified
+  // CHECK-FIXES: int const* pointee_const = &m1;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.cpp
@@ -0,0 +1,244 @@
+// RUN: %check_clang_tidy %s readability-alternative-tokens %t
+
+// A note to the reader: the whitespace in this file is important: `true&&false`
+// is lexically three tokens, but `trueandfalse` is lexed as a single
+// identifier. This test needs to make sure that the fixit applies whitespace in
+// its change.
+
+// clang-format off
+
+void logical_and()
+{
+  (void)(1&&0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1&& 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1 &&0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1 && 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+}
+
+void bitwise_and()
+{
+  (void)(0&1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0 &1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0& 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0 & 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+}
+
+void bitwise_or() {
+  (void)(0|1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0| 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0 |1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0 | 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+}
+
+void bitwise_not() {
+  (void)(~0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl 0
+
+  (void)(~ 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl 0
+}
+
+void logical_not() {
+  (void)(!0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not 0
+
+  (void)(! 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not 0
+}
+
+void logical_or() {
+  (void)(1||0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1|| 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1 ||0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1 || 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+}
+
+void bitwise_xor() {
+  (void)(0^1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0^ 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0 ^1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0 ^ 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+}
+
+struct S {
+  S operator and(S) const;
+  S operator bitand(S) const;
+  S operator bitor(S) const;
+  S operator compl() const;
+  S operator not() const;
+  S operator or(S) const;
+  S operator xor(S) const;
+};
+
+void overloaded_and() {
+  S x;
+  S y;
+
+  (void)(x&&y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: x and y
+
+  (void)(x&& y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: x and y
+
+  (void)(x &&y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: x and y
+
+  (void)(x && y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: x and y
+
+  (void)(x&y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: x bitand y
+}
+
+void overloaded_bitand() {
+  S x;
+  S y;
+
+  (void)(x|y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: x bitor y
+
+  (void)(x| y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: x bitor y
+
+  (void)(x |y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: x bitor y
+
+  (void)(x | y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: x bitor y
+}
+
+void overloaded_compl() {
+  S x;
+  S y;
+
+  (void)(~x);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl x
+
+  (void)(~ x);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl x
+}
+
+void overloaded_not() {
+  S x;
+  S y;
+
+  (void)(!x);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not x
+
+  (void)(! x);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not x
+}
+
+void overloaded_or() {
+  S x;
+  S y;
+
+  (void)(x||y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: x or y
+
+  (void)(x|| y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: x or y
+
+  (void)(x ||y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: x or y
+
+  (void)(x || y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: x or y
+}
+
+void overloaded_xor() {
+  S x;
+  S y;
+
+  (void)(x^y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: x xor y
+
+  (void)(x^ y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: x xor y
+
+  (void)(x ^y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: x xor y
+
+  (void)(x ^ y);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: x xor y
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens.c
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy %s readability-alternative-tokens %t
+
+// A note to the reader: the whitespace in this file is important: `1&&0`
+// is lexically three tokens, but `1and0` is lexed as a single
+// identifier. This test needs to make sure that the fixit applies whitespace in
+// its change.
+
+// CHECK-FIXES: #include <iso646.h>
+
+// clang-format off
+
+void logical_and()
+{
+  (void)(1&&0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1&& 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1 &&0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+
+  (void)(1 && 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 1 and 0
+}
+
+void bitwise_and()
+{
+  (void)(0&1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0 &1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0& 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+
+  (void)(0 & 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitand' for bitwise conjunctions
+  // CHECK-FIXES: 0 bitand 1
+}
+
+void bitwise_or() {
+  (void)(0|1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0| 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0 |1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+
+  (void)(0 | 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'bitor' for bitwise disjunctions
+  // CHECK-FIXES: 0 bitor 1
+}
+
+void bitwise_not() {
+  (void)(~0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl 0
+
+  (void)(~ 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'compl' for bitwise negation
+  // CHECK-FIXES: compl 0
+}
+
+void logical_not() {
+  (void)(!0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not 0
+
+  (void)(! 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use 'not' for logical negation
+  // CHECK-FIXES: not 0
+}
+
+void logical_or() {
+  (void)(1||0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1|| 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1 ||0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+
+  (void)(1 || 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'or' for logical disjunctions
+  // CHECK-FIXES: 1 or 0
+}
+
+void bitwise_xor() {
+  (void)(0^1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0^ 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0 ^1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+
+  (void)(0 ^ 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'xor' for exclusive or
+  // CHECK-FIXES: 0 xor 1
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-alternative-tokens-no-warn.c
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s readability-alternative-tokens %t
+
+// A note to the reader: the whitespace in this file is important: `1&&0`
+// is lexically three tokens, but `1and0` is lexed as a single
+// identifier. This test needs to make sure that the fixit applies whitespace in
+// its change.
+
+#include <iso646.h>
+
+// clang-format off
+
+void f1()
+{
+  (void)(1 and 0);
+  (void)(0 bitand 1);
+  (void)(0 bitor 1);
+  (void)(compl 0);
+  (void)(not 0);
+  (void)(1 or 0);
+  (void)(0 xor 1);
+
+  // This is here because clang-tidy tests seemingly need at least on CHECK-MESSAGES.
+  (void)(0 && 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'and' for logical conjunctions
+  // CHECK-FIXES: 0 and 1
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/readability-alternative-tokens.rst
@@ -0,0 +1,86 @@
+.. title:: clang-tidy - readability-alternative-tokens
+
+readability-alternative-tokens
+==================================
+
+Finds uses of symbol-based logical and bitwise operators and recommends using
+alternative tokens instead.
+
+Although symbols are the mainstream tokens in syntaxes derived from C, spelling
+out the operators can be clearer. It more clearly expresses programmer intention
+by reducing barriers for interpretation, makes small operators stand out, makes
+similar tokens more visibly distinguishable, and reduces the chances for typos.
+
+.. code-block:: c++
+
+  // warning: use 'and' for logical conjunctions
+  x && y
+
+  // warning: use 'bitand' for bitwise conjunctions
+  x & y
+
+  // warning: use 'bitor' for bitwise disjunctions
+  x | y
+
+  // warning: use 'compl' for bitwise negation
+  ~x
+
+  // warning: use 'not' for logical negation
+  not x
+
+  // warning: use 'or' for logical disjunctions
+  x || y
+
+  // warning: use 'xor' for exclusive or
+  x ^ y
+
+Supported languages
+===================
+
+* C99 and later
+* C++98 and later
+
+Limitations
+===========
+
+The following limitations are planned to be fixed within a reasonable timeframe.
+
+Configurability
+---------------
+
+A later variant of this patch will support being able to configure how logical
+and bitwise operators are spelt.
+
+Preprocessor support
+--------------------
+
+This does not currently support the preprocessor.
+
+Program composition
+-------------------
+
+This check doesn't yet account for program composition. This means that the
+warning is currently in conflict with piping C++20 ranges, as well as any other
+library that uses ``|`` as a composition operator.
+
+.. code-block:: c++
+
+  // warning: use 'bitor' for bitwise disjunctions
+  auto evens = std::views::iota(0, 1'000)
+             | std::views::filter([](int const x) { return x % 2 == 0; });
+
+  // warning: use 'bitor' for bitwise disjunctions
+  auto value = qi::int_ | qi::bool_;
+
+  // warning: use 'bitor' for bitwise disjunctions
+  std::fstream file("hello.txt", std::ios::in | std::ios::out);
+
+The reason for this limitation is because it's not yet clear how to specify to
+clang-tidy that an ``|`` is being used for composition over a genuine bitwise
+disjunction. Two ideas under consideration are:
+
+1. Have implementers apply an attribute such as ``[[clang::composable]]`` which
+   signals to the linter that ``|`` is preferred.
+
+2. Have clang-tidy users supply a list of types that can be considered as
+   composable.
Index: clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.kpp
@@ -0,0 +1,25 @@
+//===-- StringCompareCheck.cpp - clang-tidy--------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "StrictConstCorrectness.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+using ast_matchers::MatchFinder;
+
+void StrictConstCorrectness::registerMatchers(MatchFinder *Finder)
+{}
+
+void StrictConstCorrectness::check(const MatchFinder::MatchResult &Result)
+{}
+} // namespace readability
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/StrictConstCorrectness.h
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRICTCONSTCORRECTNESS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRICTCONSTCORRECTNESS_H
+
+#include "../ClangTidyCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+/// This check identifies when an object, reference, or pointee can be
+// const-qualifed.
+class StrictConstCorrectness : public ClangTidyCheck {
+public:
+  using ClangTidyCheck::ClangTidyCheck;
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRICTCONSTCORRECTNESS_H
Index: clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -9,6 +9,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "AlternativeTokensCheck.h"
 #include "AvoidConstParamsInDecls.h"
 #include "BracesAroundStatementsCheck.h"
 #include "ConstReturnTypeCheck.h"
@@ -55,6 +56,8 @@
 class ReadabilityModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<AlternativeTokensCheck>(
+        "readability-alternative-tokens");
     CheckFactories.registerCheck<AvoidConstParamsInDecls>(
         "readability-avoid-const-params-in-decls");
     CheckFactories.registerCheck<BracesAroundStatementsCheck>(
Index: clang-tools-extra/clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -4,6 +4,7 @@
   )
 
 add_clang_library(clangTidyReadabilityModule
+  AlternativeTokensCheck.cpp
   AvoidConstParamsInDecls.cpp
   BracesAroundStatementsCheck.cpp
   ConstReturnTypeCheck.cpp
Index: clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.h
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ALTERNATIVETOKENSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ALTERNATIVETOKENSCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+/// Finds uses of symbol-based logical and bitwise operators and recommends
+/// using alternative tokens instead.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-alternative-tokens.html
+class AlternativeTokensCheck : public ClangTidyCheck {
+public:
+  using ClangTidyCheck::ClangTidyCheck;
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.C99 || LangOpts.CPlusPlus;
+  }
+
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override {
+    // TODO: add support for checking preprocessor directives
+    Includer.registerPreprocessor(PP);
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  utils::IncludeInserter Includer{
+      Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM)};
+
+  void checkSpelling(const SourceManager &SM, const UnaryOperator &Op);
+  void checkSpelling(const SourceManager &SM, const BinaryOperator &Op);
+  void checkSpelling(const SourceManager &SM, const CXXOperatorCallExpr &Op);
+
+  Optional<FixItHint> includeIso646(const SourceManager &SM,
+                                    SourceLocation Loc);
+  FixItHint createReplacement(const SourceManager &SM, SourceLocation Loc,
+                              StringRef S, int CharLookahead) const;
+  char lookahead(const SourceManager &SM, SourceLocation Loc,
+                 int CharLookahead) const;
+};
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ALTERNATIVETOKENSCHECK_H
Index: clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/AlternativeTokensCheck.cpp
@@ -0,0 +1,215 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AlternativeTokensCheck.h"
+#include "../utils/IncludeInserter.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+#include <cstring>
+
+namespace clang {
+namespace tidy {
+namespace readability {
+namespace {
+AST_MATCHER(UnaryOperator, isBitwiseOrLogicalUnaryOp) {
+  return Node.getOpcode() == UnaryOperator::Opcode::UO_Not ||
+         Node.getOpcode() == UnaryOperator::Opcode::UO_LNot;
+}
+} // namespace
+
+using ast_matchers::binaryOperation;
+using ast_matchers::hasAnyOperatorName;
+using ast_matchers::MatchFinder;
+using ast_matchers::unaryOperator;
+
+void AlternativeTokensCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(unaryOperator(isBitwiseOrLogicalUnaryOp()).bind("unary"),
+                     this);
+  Finder->addMatcher(
+      binaryOperation(hasAnyOperatorName("&&", "||", "!", "&", "|", "~", "^"))
+          .bind("operator"),
+      this);
+}
+
+Optional<FixItHint>
+AlternativeTokensCheck::includeIso646(const SourceManager &SM,
+                                      SourceLocation Loc) {
+  if (!getLangOpts().C99) {
+    return llvm::None;
+  }
+
+  return Includer.createIncludeInsertion(SM.getFileID(Loc), "<iso646.h>");
+}
+
+char AlternativeTokensCheck::lookahead(const SourceManager &SM,
+                                       SourceLocation Loc,
+                                       int CharLookahead) const {
+  return *(SM.getCharacterData(Loc.getLocWithOffset(CharLookahead)));
+}
+
+FixItHint AlternativeTokensCheck::createReplacement(const SourceManager &SM,
+                                                    SourceLocation Loc,
+                                                    StringRef S,
+                                                    int CharLookahead) const {
+  // Only insert spaces if there aren't already spaces between operators
+  StringRef SpaceBefore = std::isspace(lookahead(SM, Loc, -1)) ? "" : " ";
+  StringRef SpaceAfter =
+      std::isspace(lookahead(SM, Loc, CharLookahead)) ? "" : " ";
+  return FixItHint::CreateReplacement(Loc,
+                                      (SpaceBefore + S + SpaceAfter).str());
+}
+
+void AlternativeTokensCheck::checkSpelling(const SourceManager &SM,
+                                           const UnaryOperator &Op) {
+  // TODO: make check configurable so users can decide which operators are to be
+  // symbols and which are to be words.
+
+  SourceLocation Loc = Op.getOperatorLoc();
+  assert(Loc.isValid());
+  const char *First = SM.getCharacterData(Loc);
+  assert(First != nullptr);
+  if (std::isalpha(*First) || Loc.isMacroID())
+    return;
+
+  switch (Op.getOpcode()) {
+  case UnaryOperator::Opcode::UO_Not:
+    diag(Loc, "use 'compl' for bitwise negation")
+        << createReplacement(SM, Loc, "compl", 1) << includeIso646(SM, Loc);
+    return;
+  case UnaryOperator::Opcode::UO_LNot:
+    diag(Loc, "use 'not' for logical negation")
+        << createReplacement(SM, Loc, "not", 1) << includeIso646(SM, Loc);
+    return;
+  default:
+    return;
+  }
+}
+
+void AlternativeTokensCheck::checkSpelling(const SourceManager &SM,
+                                           const BinaryOperator &Op) {
+  // TODO: make check configurable so users can decide which operators are to be
+  // symbols and which are to be words.
+
+  SourceLocation Loc = Op.getOperatorLoc();
+  assert(Loc.isValid());
+  const char *First = SM.getCharacterData(Loc);
+  assert(First != nullptr);
+  if (std::isalpha(*First) || Loc.isMacroID())
+    return;
+
+  using Opcode = BinaryOperator::Opcode;
+  Opcode OC = Op.getOpcode();
+  switch (OC) {
+  case Opcode::BO_LAnd:
+    diag(Loc, "use 'and' for logical conjunctions")
+        << createReplacement(SM, Loc, "and", 2) << includeIso646(SM, Loc);
+    break;
+  case Opcode::BO_And:
+    diag(Loc, "use 'bitand' for bitwise conjunctions")
+        << createReplacement(SM, Loc, "bitand", 1) << includeIso646(SM, Loc);
+    break;
+  case Opcode::BO_Or:
+    diag(Loc, "use 'bitor' for bitwise disjunctions")
+        << createReplacement(SM, Loc, "bitor", 1) << includeIso646(SM, Loc);
+    break;
+  case Opcode::BO_LOr:
+    diag(Loc, "use 'or' for logical disjunctions")
+        << createReplacement(SM, Loc, "or", 2) << includeIso646(SM, Loc);
+    break;
+  case Opcode::BO_Xor:
+    diag(Loc, "use 'xor' for exclusive or")
+        << createReplacement(SM, Loc, "xor", 1) << includeIso646(SM, Loc);
+    break;
+  default:
+    break;
+  }
+}
+
+void AlternativeTokensCheck::checkSpelling(const SourceManager &SM,
+                                           const CXXOperatorCallExpr &Op) {
+  // TODO: make check configurable so users can decide which operators are to be
+  // symbols and which are to be words.
+
+  // TODO: add check to make it possible to "intelligently" determine if symbol
+  // is always preferred (e.g. operator| being used for composition).
+
+  SourceLocation Loc = Op.getOperatorLoc();
+  assert(Loc.isValid());
+  const char *First = SM.getCharacterData(Loc);
+  assert(First != nullptr);
+  if (std::isalpha(*First) || Loc.isMacroID())
+    return;
+
+  using Opcode = OverloadedOperatorKind;
+  constexpr Opcode And = Opcode::OO_AmpAmp;
+  constexpr Opcode Bitand = Opcode::OO_Amp;
+  constexpr Opcode Bitor = Opcode::OO_Pipe;
+  constexpr Opcode Compl = Opcode::OO_Tilde;
+  constexpr Opcode Not = Opcode::OO_Exclaim;
+  constexpr Opcode Or = Opcode::OO_PipePipe;
+  constexpr Opcode Xor = Opcode::OO_Caret;
+
+  Opcode OC = Op.getOperator();
+  switch (OC) {
+  case And:
+    diag(Loc, "use 'and' for logical conjunctions")
+        << createReplacement(SM, Loc, "and", 2) << includeIso646(SM, Loc);
+    break;
+  case Bitand:
+    diag(Loc, "use 'bitand' for bitwise conjunctions")
+        << createReplacement(SM, Loc, "bitand", 1) << includeIso646(SM, Loc);
+    break;
+  case Bitor:
+    diag(Loc, "use 'bitor' for bitwise disjunctions")
+        << createReplacement(SM, Loc, "bitor", 1) << includeIso646(SM, Loc);
+    break;
+  case Compl:
+    diag(Loc, "use 'compl' for bitwise negation")
+        << createReplacement(SM, Loc, "compl", 1) << includeIso646(SM, Loc);
+    break;
+  case Not:
+    diag(Loc, "use 'not' for logical negation")
+        << createReplacement(SM, Loc, "not", 1) << includeIso646(SM, Loc);
+    break;
+  case Or:
+    diag(Loc, "use 'or' for logical disjunctions")
+        << createReplacement(SM, Loc, "or", 2) << includeIso646(SM, Loc);
+    break;
+  case Xor:
+    diag(Loc, "use 'xor' for exclusive or")
+        << createReplacement(SM, Loc, "xor", 1) << includeIso646(SM, Loc);
+    break;
+  default:
+    break;
+  }
+}
+
+void AlternativeTokensCheck::check(const MatchFinder::MatchResult &Result) {
+  assert(Result.SourceManager != nullptr);
+
+  if (const auto *Op = Result.Nodes.getNodeAs<UnaryOperator>("unary"))
+    return checkSpelling(*Result.SourceManager, *Op);
+
+  if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("operator"))
+    return checkSpelling(*Result.SourceManager, *Op);
+
+  if (const auto *Op = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("operator"))
+    return checkSpelling(*Result.SourceManager, *Op);
+}
+} // namespace readability
+} // namespace tidy
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to