Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the NestedNameSpecifier class, which represents
|
|
|
|
// a C++ nested-name-specifier.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/NestedNameSpecifier.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
2009-05-30 04:38:28 +08:00
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2009-03-19 11:51:16 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-03-27 07:50:42 +08:00
|
|
|
#include <cassert>
|
2009-03-19 11:51:16 +08:00
|
|
|
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::FindOrInsert(ASTContext &Context,
|
|
|
|
const NestedNameSpecifier &Mockup) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
Mockup.Profile(ID);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
NestedNameSpecifier *NNS
|
|
|
|
= Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (!NNS) {
|
2009-04-01 08:28:59 +08:00
|
|
|
NNS = new (Context, 4) NestedNameSpecifier(Mockup);
|
2009-03-27 07:50:42 +08:00
|
|
|
Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NNS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
|
|
|
|
IdentifierInfo *II) {
|
|
|
|
assert(II && "Identifier cannot be NULL");
|
|
|
|
assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
|
|
|
|
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
|
|
|
Mockup.Prefix.setInt(Identifier);
|
|
|
|
Mockup.Specifier = II;
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
|
|
|
|
NamespaceDecl *NS) {
|
|
|
|
assert(NS && "Namespace cannot be NULL");
|
|
|
|
assert((!Prefix ||
|
|
|
|
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
|
|
|
|
"Broken nested name specifier");
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
|
|
|
Mockup.Prefix.setInt(Namespace);
|
|
|
|
Mockup.Specifier = NS;
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
|
|
|
NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
|
|
|
|
bool Template, Type *T) {
|
|
|
|
assert(T && "Type cannot be NULL");
|
|
|
|
NestedNameSpecifier Mockup;
|
2009-04-01 08:28:59 +08:00
|
|
|
Mockup.Prefix.setPointer(Prefix);
|
|
|
|
Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
|
|
|
|
Mockup.Specifier = T;
|
2009-03-27 07:50:42 +08:00
|
|
|
return FindOrInsert(Context, Mockup);
|
|
|
|
}
|
2009-03-19 11:51:16 +08:00
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
|
|
|
|
if (!Context.GlobalNestedNameSpecifier)
|
2009-04-01 08:28:59 +08:00
|
|
|
Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
|
2009-03-27 07:50:42 +08:00
|
|
|
return Context.GlobalNestedNameSpecifier;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Whether this nested name specifier refers to a dependent
|
|
|
|
/// type or not.
|
|
|
|
bool NestedNameSpecifier::isDependent() const {
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
// Identifier specifiers always represent dependent types
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case Namespace:
|
|
|
|
case Global:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TypeSpec:
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
return getAsType()->isDependentType();
|
2009-03-19 11:51:16 +08:00
|
|
|
}
|
2009-03-27 07:50:42 +08:00
|
|
|
|
|
|
|
// Necessary to suppress a GCC warning.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Print this nested name specifier to the given output
|
|
|
|
/// stream.
|
2009-05-30 04:38:28 +08:00
|
|
|
void
|
|
|
|
NestedNameSpecifier::print(llvm::raw_ostream &OS,
|
|
|
|
const PrintingPolicy &Policy) const {
|
2009-04-01 08:28:59 +08:00
|
|
|
if (getPrefix())
|
2009-05-30 04:38:28 +08:00
|
|
|
getPrefix()->print(OS, Policy);
|
2009-03-27 07:50:42 +08:00
|
|
|
|
|
|
|
switch (getKind()) {
|
|
|
|
case Identifier:
|
|
|
|
OS << getAsIdentifier()->getName();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Namespace:
|
|
|
|
OS << getAsNamespace()->getIdentifier()->getName();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Global:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TypeSpecWithTemplate:
|
|
|
|
OS << "template ";
|
|
|
|
// Fall through to print the type.
|
|
|
|
|
|
|
|
case TypeSpec: {
|
|
|
|
std::string TypeStr;
|
|
|
|
Type *T = getAsType();
|
|
|
|
|
2009-05-30 04:38:28 +08:00
|
|
|
PrintingPolicy InnerPolicy(Policy);
|
|
|
|
InnerPolicy.SuppressTagKind = true;
|
2009-08-26 08:04:55 +08:00
|
|
|
|
|
|
|
// Nested-name-specifiers are intended to contain minimally-qualified
|
|
|
|
// types. An actual QualifiedNameType will not occur, since we'll store
|
|
|
|
// just the type that is referred to in the nested-name-specifier (e.g.,
|
|
|
|
// a TypedefType, TagType, etc.). However, when we are dealing with
|
|
|
|
// dependent template-id types (e.g., Outer<T>::template Inner<U>),
|
|
|
|
// the type requires its own nested-name-specifier for uniqueness, so we
|
|
|
|
// suppress that nested-name-specifier during printing.
|
|
|
|
assert(!isa<QualifiedNameType>(T) &&
|
|
|
|
"Qualified name type in nested-name-specifier");
|
|
|
|
if (const TemplateSpecializationType *SpecType
|
|
|
|
= dyn_cast<TemplateSpecializationType>(T)) {
|
|
|
|
// Print the template name without its corresponding
|
|
|
|
// nested-name-specifier.
|
|
|
|
SpecType->getTemplateName().print(OS, InnerPolicy, true);
|
|
|
|
|
|
|
|
// Print the template argument list.
|
|
|
|
TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
SpecType->getArgs(),
|
|
|
|
SpecType->getNumArgs(),
|
|
|
|
InnerPolicy);
|
|
|
|
} else {
|
|
|
|
// Print the type normally
|
|
|
|
T->getAsStringInternal(TypeStr, InnerPolicy);
|
|
|
|
}
|
2009-03-27 07:50:42 +08:00
|
|
|
OS << TypeStr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << "::";
|
|
|
|
}
|
|
|
|
|
|
|
|
void NestedNameSpecifier::Destroy(ASTContext &Context) {
|
|
|
|
this->~NestedNameSpecifier();
|
|
|
|
Context.Deallocate((void *)this);
|
2009-03-19 11:51:16 +08:00
|
|
|
}
|
2009-03-28 07:10:48 +08:00
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
void NestedNameSpecifier::dump(const LangOptions &LO) {
|
|
|
|
print(llvm::errs(), PrintingPolicy(LO));
|
2009-03-28 07:10:48 +08:00
|
|
|
}
|