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