brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 5613cea Raw
105 lines · cpp
1//===--- RawStringLiteral.cpp ------------------------------------*- C++-*-===//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#include "ParsedAST.h"9#include "refactor/Tweak.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Stmt.h"12#include "clang/Basic/LangOptions.h"13#include "clang/Basic/SourceLocation.h"14#include "clang/Basic/SourceManager.h"15#include "clang/Tooling/Core/Replacement.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Casting.h"18#include "llvm/Support/Error.h"19 20namespace clang {21namespace clangd {22namespace {23/// Converts a string literal to a raw string.24/// Before:25///   printf("\"a\"\nb");26///          ^^^^^^^^^27/// After:28///   printf(R"("a"29/// b)");30class RawStringLiteral : public Tweak {31public:32  const char *id() const final;33 34  bool prepare(const Selection &Inputs) override;35  Expected<Effect> apply(const Selection &Inputs) override;36  std::string title() const override { return "Convert to raw string"; }37  llvm::StringLiteral kind() const override {38    return CodeAction::REFACTOR_KIND;39  }40 41private:42  const clang::StringLiteral *Str = nullptr;43};44 45REGISTER_TWEAK(RawStringLiteral)46 47static bool isFeatureAvailable(const ASTContext &Context) {48  // Raw strings are available only for C++11 or later versions, and they are49  // not available for C.50  return Context.getLangOpts().CPlusPlus11;51}52 53static bool isNormalString(const StringLiteral &Str, SourceLocation Cursor,54                          SourceManager &SM) {55  // All chunks must be normal ASCII strings, not u8"..." etc.56  if (!Str.isOrdinary())57    return false;58  SourceLocation LastTokenBeforeCursor;59  for (auto I = Str.tokloc_begin(), E = Str.tokloc_end(); I != E; ++I) {60    if (I->isMacroID()) // No tokens in the string may be macro expansions.61      return false;62    if (SM.isBeforeInTranslationUnit(*I, Cursor) || *I == Cursor)63      LastTokenBeforeCursor = *I;64  }65  // Token we care about must be a normal "string": not raw, u8, etc.66  const char* Data = SM.getCharacterData(LastTokenBeforeCursor);67  return Data && *Data == '"';68}69 70static bool needsRaw(llvm::StringRef Content) {71  return Content.find_first_of("\"\n\t") != StringRef::npos;72}73 74static bool canBeRaw(llvm::StringRef Content) {75  for (char C : Content)76    if (!llvm::isPrint(C) && C != '\n' && C != '\t')77      return false;78  return !Content.contains(")\"");79}80 81bool RawStringLiteral::prepare(const Selection &Inputs) {82  if (!isFeatureAvailable(Inputs.AST->getASTContext())) {83    return false;84  }85  const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();86  if (!N)87    return false;88  Str = dyn_cast_or_null<StringLiteral>(N->ASTNode.get<Stmt>());89  return Str &&90         isNormalString(*Str, Inputs.Cursor, Inputs.AST->getSourceManager()) &&91         needsRaw(Str->getBytes()) && canBeRaw(Str->getBytes());92}93 94Expected<Tweak::Effect> RawStringLiteral::apply(const Selection &Inputs) {95  auto &SM = Inputs.AST->getSourceManager();96  auto Reps = tooling::Replacements(97      tooling::Replacement(SM, Str, ("R\"(" + Str->getBytes() + ")\"").str(),98                           Inputs.AST->getLangOpts()));99  return Effect::mainFileEdit(SM, std::move(Reps));100}101 102} // namespace103} // namespace clangd104} // namespace clang105