brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · 2b9183c Raw
113 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "FunctionNamingCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "llvm/Support/Regex.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::google::objc {16 17static std::string validFunctionNameRegex(bool RequirePrefix) {18  // Allow the following name patterns for all functions:19  // • ABFoo (prefix + UpperCamelCase)20  // • ABURL (prefix + capitalized acronym/initialism)21  //22  // If no prefix is required, additionally allow the following name patterns:23  // • Foo (UpperCamelCase)24  // • URL (capitalized acronym/initialism)25  //26  // The function name following the prefix can contain standard and27  // non-standard capitalized character sequences including acronyms,28  // initialisms, and prefixes of symbols (e.g., UIColorFromNSString). For this29  // reason, the regex only verifies that the function name after the prefix30  // begins with a capital letter followed by an arbitrary sequence of31  // alphanumeric characters.32  //33  // If a prefix is required, the regex checks for a capital letter followed by34  // another capital letter or number that is part of the prefix and another35  // capital letter or number that begins the name following the prefix.36  const std::string FunctionNameMatcher =37      std::string(RequirePrefix ? "[A-Z][A-Z0-9]+" : "") + "[A-Z][a-zA-Z0-9]*";38  return std::string("::(") + FunctionNameMatcher + ")$";39}40 41/// For now we will only fix functions of static storage class with names like42/// 'functionName' or 'function_name' and convert them to 'FunctionName'. For43/// other cases the user must determine an appropriate name on their own.44static FixItHint generateFixItHint(const FunctionDecl *Decl) {45  // A fixit can be generated for functions of static storage class but46  // otherwise the check cannot determine the appropriate function name prefix47  // to use.48  if (Decl->getStorageClass() != SC_Static)49    return {};50 51  const StringRef Name = Decl->getName();52  std::string NewName = Decl->getName().str();53 54  size_t Index = 0;55  bool AtWordBoundary = true;56  while (Index < NewName.size()) {57    const char Ch = NewName[Index];58    if (isalnum(Ch)) {59      // Capitalize the first letter after every word boundary.60      if (AtWordBoundary) {61        NewName[Index] = toupper(NewName[Index]);62        AtWordBoundary = false;63      }64 65      // Advance the index after every alphanumeric character.66      Index++;67    } else {68      // Strip out any characters other than alphanumeric characters.69      NewName.erase(Index, 1);70      AtWordBoundary = true;71    }72  }73 74  // Generate a fixit hint if the new name is different.75  if (NewName != Name)76    return FixItHint::CreateReplacement(77        CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),78        llvm::StringRef(NewName));79 80  return {};81}82 83void FunctionNamingCheck::registerMatchers(MatchFinder *Finder) {84  // Enforce Objective-C function naming conventions on all functions except:85  // • Functions defined in system headers.86  // • C++ member functions.87  // • Namespaced functions.88  // • Implicitly defined functions.89  // • The main function.90  Finder->addMatcher(91      functionDecl(92          unless(anyOf(isExpansionInSystemHeader(), cxxMethodDecl(),93                       hasAncestor(namespaceDecl()), isMain(), isImplicit(),94                       matchesName(validFunctionNameRegex(true)),95                       allOf(isStaticStorageClass(),96                             matchesName(validFunctionNameRegex(false))))))97          .bind("function"),98      this);99}100 101void FunctionNamingCheck::check(const MatchFinder::MatchResult &Result) {102  const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("function");103 104  const bool IsGlobal = MatchedDecl->getStorageClass() != SC_Static;105  diag(MatchedDecl->getLocation(),106       "%select{static function|function in global namespace}1 named %0 must "107       "%select{be in|have an appropriate prefix followed by}1 Pascal case as "108       "required by Google Objective-C style guide")109      << MatchedDecl << IsGlobal << generateFixItHint(MatchedDecl);110}111 112} // namespace clang::tidy::google::objc113