brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.0 KiB · 4ac3f3a Raw
237 lines · cpp
1//===- FixitUtil.cpp ------------------------------------------------------===//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 "clang/Analysis/Support/FixitUtil.h"10#include "clang/ASTMatchers/ASTMatchers.h"11 12using namespace llvm;13using namespace clang;14using namespace ast_matchers;15 16// Returns the text of the pointee type of `T` from a `VarDecl` of a pointer17// type. The text is obtained through from `TypeLoc`s.  Since `TypeLoc` does not18// have source ranges of qualifiers ( The `QualTypeLoc` looks hacky too me19// :( ), `Qualifiers` of the pointee type is returned separately through the20// output parameter `QualifiersToAppend`.21std::optional<std::string>22clang::getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM,23                          const LangOptions &LangOpts,24                          std::optional<Qualifiers> *QualifiersToAppend) {25  QualType Ty = VD->getType();26  QualType PteTy;27 28  assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&29         "Expecting a VarDecl of type of pointer to object type");30  PteTy = Ty->getPointeeType();31 32  TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();33  TypeLoc PteTyLoc;34 35  // We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns36  // the `TypeLoc` of the pointee type:37  switch (TyLoc.getTypeLocClass()) {38  case TypeLoc::ConstantArray:39  case TypeLoc::IncompleteArray:40  case TypeLoc::VariableArray:41  case TypeLoc::DependentSizedArray:42  case TypeLoc::Decayed:43    assert(isa<ParmVarDecl>(VD) && "An array type shall not be treated as a "44                                   "pointer type unless it decays.");45    PteTyLoc = TyLoc.getNextTypeLoc();46    break;47  case TypeLoc::Pointer:48    PteTyLoc = TyLoc.castAs<PointerTypeLoc>().getPointeeLoc();49    break;50  default:51    return std::nullopt;52  }53  if (PteTyLoc.isNull())54    // Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,55    // when the pointer type is `auto`.56    return std::nullopt;57 58  // TODO check59  SourceLocation IdentLoc = VD->getLocation();60 61  if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {62    // We are expecting these locations to be valid. But in some cases, they are63    // not all valid. It is a Clang bug to me and we are not responsible for64    // fixing it.  So we will just give up for now when it happens.65    return std::nullopt;66  }67 68  // Note that TypeLoc.getEndLoc() returns the begin location of the last token:69  SourceLocation PteEndOfTokenLoc =70      Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);71 72  if (!PteEndOfTokenLoc.isValid())73    // Sometimes we cannot get the end location of the pointee type, e.g., when74    // there are macros involved.75    return std::nullopt;76  if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc) &&77      PteEndOfTokenLoc != IdentLoc) {78    // We only deal with the cases where the source text of the pointee type79    // appears on the left-hand side of the variable identifier completely,80    // including the following forms:81    // `T ident`,82    // `T ident[]`, where `T` is any type.83    // Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.84    return std::nullopt;85  }86  if (PteTy.hasQualifiers()) {87    // TypeLoc does not provide source ranges for qualifiers (it says it's88    // intentional but seems fishy to me), so we cannot get the full text89    // `PteTy` via source ranges.90    *QualifiersToAppend = PteTy.getQualifiers();91  }92  return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)93      ->str();94}95 96// returns text of pointee to pointee (T*&)97std::optional<std::string>98getPointee2TypeText(const DeclaratorDecl *VD, const SourceManager &SM,99                    const LangOptions &LangOpts,100                    std::optional<Qualifiers> *QualifiersToAppend) {101 102  QualType Ty = VD->getType();103  assert(Ty->isReferenceType() &&104         "Expecting a VarDecl of reference to pointer type");105 106  Ty = Ty->getPointeeType();107  QualType PteTy;108 109  assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&110         "Expecting a VarDecl of type of pointer to object type");111  PteTy = Ty->getPointeeType();112 113  TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();114  TypeLoc PtrTyLoc;115  TypeLoc PteTyLoc;116 117  // We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns118  // the `TypeLoc` of the pointee type:119  switch (TyLoc.getTypeLocClass()) {120  case TypeLoc::ConstantArray:121  case TypeLoc::IncompleteArray:122  case TypeLoc::VariableArray:123  case TypeLoc::DependentSizedArray:124  case TypeLoc::LValueReference:125    PtrTyLoc = TyLoc.castAs<ReferenceTypeLoc>().getPointeeLoc();126    if (PtrTyLoc.getTypeLocClass() == TypeLoc::Pointer) {127      PteTyLoc = PtrTyLoc.castAs<PointerTypeLoc>().getPointeeLoc();128      break;129    }130    return std::nullopt;131    break;132  default:133    return std::nullopt;134  }135  if (PteTyLoc.isNull())136    // Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,137    // when the pointer type is `auto`.138    return std::nullopt;139 140  // TODO make sure this works141  SourceLocation IdentLoc = VD->getLocation();142 143  if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {144    // We are expecting these locations to be valid. But in some cases, they are145    // not all valid. It is a Clang bug to me and we are not responsible for146    // fixing it.  So we will just give up for now when it happens.147    return std::nullopt;148  }149 150  // Note that TypeLoc.getEndLoc() returns the begin location of the last token:151  SourceLocation PteEndOfTokenLoc =152      Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);153 154  if (!PteEndOfTokenLoc.isValid())155    // Sometimes we cannot get the end location of the pointee type, e.g., when156    // there are macros involved.157    return std::nullopt;158  if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {159    // We only deal with the cases where the source text of the pointee type160    // appears on the left-hand side of the variable identifier completely,161    // including the following forms:162    // `T ident`,163    // `T ident[]`, where `T` is any type.164    // Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.165    return std::nullopt;166  }167  if (PteTy.hasQualifiers()) {168    // TypeLoc does not provide source ranges for qualifiers (it says it's169    // intentional but seems fishy to me), so we cannot get the full text170    // `PteTy` via source ranges.171    *QualifiersToAppend = PteTy.getQualifiers();172  }173  return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)174      ->str();175}176 177SourceLocation clang::getBeginLocOfNestedIdentifier(const DeclaratorDecl *D) {178  if (D->getQualifier()) {179    return D->getQualifierLoc().getBeginLoc();180  }181  return getVarDeclIdentifierLoc(D);182}183 184// Returns the literal text in `SourceRange SR`, if `SR` is a valid range.185std::optional<StringRef> clang::getRangeText(SourceRange SR,186                                             const SourceManager &SM,187                                             const LangOptions &LangOpts) {188  bool Invalid = false;189  CharSourceRange CSR = CharSourceRange::getCharRange(SR);190  StringRef Text = Lexer::getSourceText(CSR, SM, LangOpts, &Invalid);191 192  if (!Invalid)193    return Text;194  return std::nullopt;195}196 197// Returns the literal text of the identifier of the given variable declaration.198std::optional<StringRef>199clang::getVarDeclIdentifierText(const DeclaratorDecl *VD,200                                const SourceManager &SM,201                                const LangOptions &LangOpts) {202  SourceLocation ParmIdentBeginLoc = getBeginLocOfNestedIdentifier(VD);203  SourceLocation ParmIdentEndLoc =204      Lexer::getLocForEndOfToken(getVarDeclIdentifierLoc(VD), 0, SM, LangOpts);205 206  if (VD->getQualifier()) {207    ParmIdentBeginLoc = VD->getQualifierLoc().getBeginLoc();208  }209 210  if (ParmIdentEndLoc.isMacroID() &&211      !Lexer::isAtEndOfMacroExpansion(ParmIdentEndLoc, SM, LangOpts))212    return std::nullopt;213  return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc}, SM, LangOpts);214}215 216// Return text representation of an `Expr`.217std::optional<StringRef> clang::getExprText(const Expr *E,218                                            const SourceManager &SM,219                                            const LangOptions &LangOpts) {220  std::optional<SourceLocation> LastCharLoc = getPastLoc(E, SM, LangOpts);221 222  if (LastCharLoc)223    return Lexer::getSourceText(224        CharSourceRange::getCharRange(E->getBeginLoc(), *LastCharLoc), SM,225        LangOpts);226 227  return std::nullopt;228}229 230// Returns the begin location of the identifier of the given variable231// declaration.232SourceLocation clang::getVarDeclIdentifierLoc(const DeclaratorDecl *VD) {233  // According to the implementation of `VarDecl`, `VD->getLocation()` actually234  // returns the begin location of the identifier of the declaration:235  return VD->getLocation();236}237