brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.7 KiB · c6af91f Raw
354 lines · cpp
1//===- NestedNameSpecifier.cpp - C++ nested name specifiers ---------------===//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//  This file defines the NestedNameSpecifier class, which represents10//  a C++ nested-name-specifier.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/NestedNameSpecifier.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/DependenceFlags.h"19#include "clang/AST/PrettyPrinter.h"20#include "clang/AST/TemplateName.h"21#include "clang/AST/Type.h"22#include "clang/AST/TypeLoc.h"23#include "clang/Basic/LLVM.h"24#include "clang/Basic/LangOptions.h"25#include "clang/Basic/SourceLocation.h"26#include "llvm/ADT/FoldingSet.h"27#include "llvm/Support/Compiler.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Support/raw_ostream.h"30#include <algorithm>31#include <cassert>32#include <cstdlib>33#include <cstring>34 35using namespace clang;36 37const NamespaceAndPrefixStorage *38NestedNameSpecifier::MakeNamespaceAndPrefixStorage(39    const ASTContext &Ctx, const NamespaceBaseDecl *Namespace,40    NestedNameSpecifier Prefix) {41  llvm::FoldingSetNodeID ID;42  NamespaceAndPrefixStorage::Profile(ID, Namespace, Prefix);43 44  void *InsertPos = nullptr;45  NamespaceAndPrefixStorage *S =46      Ctx.NamespaceAndPrefixStorages.FindNodeOrInsertPos(ID, InsertPos);47  if (!S) {48    S = new (Ctx, alignof(NamespaceAndPrefixStorage))49        NamespaceAndPrefixStorage(Namespace, Prefix);50    Ctx.NamespaceAndPrefixStorages.InsertNode(S, InsertPos);51  }52  return S;53}54 55bool NestedNameSpecifier::isFullyQualified() const {56  switch (getKind()) {57  case NestedNameSpecifier::Kind::Global:58    return true;59  case NestedNameSpecifier::Kind::Null:60  case NestedNameSpecifier::Kind::MicrosoftSuper:61    return false;62  case NestedNameSpecifier::Kind::Namespace:63    return getAsNamespaceAndPrefix().Prefix.isFullyQualified();64  case NestedNameSpecifier::Kind::Type:65    return getAsType()->getPrefix().isFullyQualified();66  }67  llvm_unreachable("Invalid NNS Kind!");68}69 70NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const {71  switch (getKind()) {72  case Kind::Null:73  case Kind::Global:74  case Kind::Namespace:75    return NestedNameSpecifierDependence::None;76  case Kind::MicrosoftSuper: {77    CXXRecordDecl *RD = getAsMicrosoftSuper();78    return RD->isDependentContext()79               ? NestedNameSpecifierDependence::DependentInstantiation |80                     NestedNameSpecifierDependence::Dependent81               : NestedNameSpecifierDependence::None;82  }83  case Kind::Type:84    return toNestedNameSpecifierDependence(getAsType()->getDependence());85  }86  llvm_unreachable("Invalid NNS Kind!");87}88 89/// Print this nested name specifier to the given output90/// stream.91void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,92                                bool ResolveTemplateArguments,93                                bool PrintFinalScopeResOp) const {94  switch (getKind()) {95  case Kind::Namespace: {96    auto [Namespace, Prefix] = getAsNamespaceAndPrefix();97    Prefix.print(OS, Policy);98    if (const auto *NS = dyn_cast<NamespaceDecl>(Namespace)) {99      assert(!NS->isAnonymousNamespace());100      OS << NS->getName();101    } else {102      OS << cast<NamespaceAliasDecl>(Namespace)->getName();103    }104    break;105  }106  case Kind::Global:107    OS << "::";108    return;109  case Kind::MicrosoftSuper:110    OS << "__super";111    break;112  case Kind::Type: {113    PrintingPolicy InnerPolicy(Policy);114    InnerPolicy.SuppressTagKeyword = true;115    QualType(getAsType(), 0).print(OS, InnerPolicy);116    break;117  }118  case Kind::Null:119    return;120  }121  if (PrintFinalScopeResOp)122    OS << "::";123}124 125LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream *OS,126                                                const LangOptions *LO) const {127  print(OS ? *OS : llvm::errs(), LO ? *LO : LangOptions());128}129 130LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const {131  dump(/*OS=*/nullptr, &LO);132}133LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const {134  dump(&OS);135}136LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS,137                                                const LangOptions &LO) const {138  dump(&OS, &LO);139}140 141SourceLocation NestedNameSpecifierLoc::getBeginLoc() const {142  if (!Qualifier)143    return SourceLocation();144 145  NestedNameSpecifierLoc First = *this;146  while (NestedNameSpecifierLoc Prefix = First.getAsNamespaceAndPrefix().Prefix)147    First = Prefix;148  return First.getLocalSourceRange().getBegin();149}150 151static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,152                   unsigned &BufferCapacity) {153  if (Start == End)154    return;155 156  if (BufferSize + (End - Start) > BufferCapacity) {157    // Reallocate the buffer.158    unsigned NewCapacity = std::max(159        (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2),160        (unsigned)(BufferSize + (End - Start)));161    if (!BufferCapacity) {162      char *NewBuffer = static_cast<char *>(llvm::safe_malloc(NewCapacity));163      if (Buffer)164        memcpy(NewBuffer, Buffer, BufferSize);165      Buffer = NewBuffer;166    } else {167      Buffer = static_cast<char *>(llvm::safe_realloc(Buffer, NewCapacity));168    }169    BufferCapacity = NewCapacity;170  }171  assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy");172  memcpy(Buffer + BufferSize, Start, End - Start);173  BufferSize += End - Start;174}175 176/// Save a source location to the given buffer.177static void SaveSourceLocation(SourceLocation Loc, char *&Buffer,178                               unsigned &BufferSize, unsigned &BufferCapacity) {179  SourceLocation::UIntTy Raw = Loc.getRawEncoding();180  Append(reinterpret_cast<char *>(&Raw),181         reinterpret_cast<char *>(&Raw) + sizeof(Raw), Buffer, BufferSize,182         BufferCapacity);183}184 185/// Save a pointer to the given buffer.186static void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,187                        unsigned &BufferCapacity) {188  Append(reinterpret_cast<char *>(&Ptr),189         reinterpret_cast<char *>(&Ptr) + sizeof(void *),190         Buffer, BufferSize, BufferCapacity);191}192 193NestedNameSpecifierLocBuilder::194NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)195    : Representation(Other.Representation) {196  if (!Other.Buffer)197    return;198 199  if (Other.BufferCapacity == 0) {200    // Shallow copy is okay.201    Buffer = Other.Buffer;202    BufferSize = Other.BufferSize;203    return;204  }205 206  // Deep copy207  Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize,208         BufferCapacity);209}210 211NestedNameSpecifierLocBuilder &212NestedNameSpecifierLocBuilder::213operator=(const NestedNameSpecifierLocBuilder &Other) {214  Representation = Other.Representation;215 216  if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {217    // Re-use our storage.218    BufferSize = Other.BufferSize;219    memcpy(Buffer, Other.Buffer, BufferSize);220    return *this;221  }222 223  // Free our storage, if we have any.224  if (BufferCapacity) {225    free(Buffer);226    BufferCapacity = 0;227  }228 229  if (!Other.Buffer) {230    // Empty.231    Buffer = nullptr;232    BufferSize = 0;233    return *this;234  }235 236  if (Other.BufferCapacity == 0) {237    // Shallow copy is okay.238    Buffer = Other.Buffer;239    BufferSize = Other.BufferSize;240    return *this;241  }242 243  // Deep copy.244  BufferSize = 0;245  Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize,246         BufferCapacity);247  return *this;248}249 250void NestedNameSpecifierLocBuilder::Make(ASTContext &Context, TypeLoc TL,251                                         SourceLocation ColonColonLoc) {252  assert(!Representation);253  Representation = NestedNameSpecifier(TL.getTypePtr());254 255  // Push source-location info into the buffer.256  SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);257  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);258}259 260void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,261                                           const NamespaceBaseDecl *Namespace,262                                           SourceLocation NamespaceLoc,263                                           SourceLocation ColonColonLoc) {264  Representation = NestedNameSpecifier(Context, Namespace, Representation);265 266  // Push source-location info into the buffer.267  SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);268  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);269}270 271void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,272                                               SourceLocation ColonColonLoc) {273  assert(!Representation && "Already have a nested-name-specifier!?");274  Representation = NestedNameSpecifier::getGlobal();275 276  // Push source-location info into the buffer.277  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);278}279 280void NestedNameSpecifierLocBuilder::MakeMicrosoftSuper(281    ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc,282    SourceLocation ColonColonLoc) {283  Representation = NestedNameSpecifier(RD);284 285  // Push source-location info into the buffer.286  SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity);287  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);288}289 290void NestedNameSpecifierLocBuilder::PushTrivial(ASTContext &Context,291                                                NestedNameSpecifier Qualifier,292                                                SourceRange R) {293  // Construct bogus (but well-formed) source information for the294  // nested-name-specifier.295  switch (Qualifier.getKind()) {296  case NestedNameSpecifier::Kind::Null:297    return;298  case NestedNameSpecifier::Kind::Namespace: {299    auto [_1, Prefix] = Qualifier.getAsNamespaceAndPrefix();300    PushTrivial(Context, Prefix, R.getBegin());301    SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);302    break;303  }304  case NestedNameSpecifier::Kind::Type: {305    TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(306        QualType(Qualifier.getAsType(), 0), R.getBegin());307    SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,308                BufferCapacity);309    break;310  }311  case NestedNameSpecifier::Kind::Global:312  case NestedNameSpecifier::Kind::MicrosoftSuper:313    break;314  }315  SaveSourceLocation(R.getEnd(), Buffer, BufferSize, BufferCapacity);316}317 318void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {319  if (BufferCapacity)320    free(Buffer);321 322  if (!Other) {323    Representation = std::nullopt;324    BufferSize = 0;325    return;326  }327 328  // Rather than copying the data (which is wasteful), "adopt" the329  // pointer (which points into the ASTContext) but set the capacity to zero to330  // indicate that we don't own it.331  Representation = Other.getNestedNameSpecifier();332  Buffer = static_cast<char *>(Other.getOpaqueData());333  BufferSize = Other.getDataLength();334  BufferCapacity = 0;335}336 337NestedNameSpecifierLoc338NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const {339  if (!Representation)340    return NestedNameSpecifierLoc();341 342  // If we adopted our data pointer from elsewhere in the AST context, there's343  // no need to copy the memory.344  if (BufferCapacity == 0)345    return NestedNameSpecifierLoc(Representation, Buffer);346 347  // FIXME: After copying the source-location information, should we free348  // our (temporary) buffer and adopt the ASTContext-allocated memory?349  // Doing so would optimize repeated calls to getWithLocInContext().350  void *Mem = Context.Allocate(BufferSize, alignof(void *));351  memcpy(Mem, Buffer, BufferSize);352  return NestedNameSpecifierLoc(Representation, Mem);353}354