bool checkDeclForNamespace(const CXXRecordDecl *decl, std::string concreteNamespace) { const DeclContext * context = decl->getCanonicalDecl()->getDeclContext(); if (context->isNamespace()) { NamespaceDecl * nameDecl = NamespaceDecl::castFromDeclContext(context); if (nameDecl->getNameAsString() == concreteNamespace) { return true; } } return false; }
NamespaceDecl *Sema::ActOnEnterRogerFileScopeNamespace(Scope *NamespcScope) { IdentifierInfo &II = Context.Idents.get("roger file scope namespace"); NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, false, SourceLocation(), SourceLocation(), &II, 0); Namespc->IsRogerNamespace = true; Namespc->setLexicalDeclContext(CurContext); //DeclContext->addDecl(Namespc); PushDeclContext(NamespcScope, Namespc); return Namespc; }
void DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){ Contexts.clear(); if (DeclKind != Decl::Namespace) { Contexts.push_back(this); return; } NamespaceDecl *Self = static_cast<NamespaceDecl *>(this); for (NamespaceDecl *N = Self->getMostRecentDecl(); N; N = N->getPreviousDecl()) Contexts.push_back(N); std::reverse(Contexts.begin(), Contexts.end()); }
static bool singleNamedNamespaceChild(const NamespaceDecl &ND) { NamespaceDecl::decl_range Decls = ND.decls(); if (std::distance(Decls.begin(), Decls.end()) != 1) return false; const auto *ChildNamespace = dyn_cast<const NamespaceDecl>(*Decls.begin()); return ChildNamespace && !anonymousOrInlineNamespace(*ChildNamespace); }
// TODO: Add classes with a finalize() method that specialize FinalizerTrait. bool RecordInfo::NeedsFinalization() { if (does_need_finalization_ == kNotComputed) { // Rely on hasNonTrivialDestructor(), but if the only // identifiable reason for it being true is the presence // of a safely ignorable class as a direct base, // or we're processing such an 'ignorable' class, then it does // not need finalization. does_need_finalization_ = record_->hasNonTrivialDestructor() ? kTrue : kFalse; if (!does_need_finalization_) return does_need_finalization_; // Processing a class with a safely-ignorable destructor. NamespaceDecl* ns = dyn_cast<NamespaceDecl>(record_->getDeclContext()); if (ns && Config::HasIgnorableDestructor(ns->getName(), name_)) { does_need_finalization_ = kFalse; return does_need_finalization_; } CXXDestructorDecl* dtor = record_->getDestructor(); if (dtor && dtor->isUserProvided()) return does_need_finalization_; for (Fields::iterator it = GetFields().begin(); it != GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) return does_need_finalization_; } for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { if (it->second.info()->NeedsFinalization()) return does_need_finalization_; } // Destructor was non-trivial due to bases with destructors that // can be safely ignored. Hence, no need for finalization. does_need_finalization_ = kFalse; } return does_need_finalization_; }
static bool anonymousOrInlineNamespace(const NamespaceDecl &ND) { return ND.isAnonymousNamespace() || ND.isInlineNamespace(); }
Edge* RecordInfo::CreateEdge(const Type* type) { if (!type) { return 0; } if (type->isPointerType() || type->isReferenceType()) { if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull())) return new RawPtr(ptr, false, type->isReferenceType()); return 0; } RecordInfo* info = cache_->Lookup(type); // If the type is neither a pointer or a C++ record we ignore it. if (!info) { return 0; } TemplateArgs args; if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new RawPtr(ptr, true, false); return 0; } if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new RefPtr(ptr); return 0; } if (Config::IsOwnPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new OwnPtr(ptr); return 0; } if (Config::IsMember(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new Member(ptr); return 0; } if (Config::IsWeakMember(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new WeakMember(ptr); return 0; } if (Config::IsPersistent(info->name())) { // Persistent might refer to v8::Persistent, so check the name space. // TODO: Consider using a more canonical identification than names. NamespaceDecl* ns = dyn_cast<NamespaceDecl>(info->record()->getDeclContext()); if (!ns || ns->getName() != "blink") return 0; if (!info->GetTemplateArgs(1, &args)) return 0; if (Edge* ptr = CreateEdge(args[0])) return new Persistent(ptr); return 0; } if (Config::IsGCCollection(info->name()) || Config::IsWTFCollection(info->name())) { bool is_root = Config::IsPersistentGCCollection(info->name()); bool on_heap = is_root || info->IsHeapAllocatedCollection(); size_t count = Config::CollectionDimension(info->name()); if (!info->GetTemplateArgs(count, &args)) return 0; Collection* edge = new Collection(info, on_heap, is_root); for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { if (Edge* member = CreateEdge(*it)) { edge->members().push_back(member); } // TODO: Handle the case where we fail to create an edge (eg, if the // argument is a primitive type or just not fully known yet). } return edge; } return new Value(info); }
Edge* RecordInfo::CreateEdge(const Type* type) { if (!type) { return 0; } if (type->isPointerType()) { if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull())) return new RawPtr(ptr); return 0; } RecordInfo* info = cache_->Lookup(type); // If the type is neither a pointer or a C++ record we ignore it. if (!info) { return 0; } TemplateArgs args; if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new RawPtr(ptr); return 0; } if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new RefPtr(ptr); return 0; } if (Config::IsOwnPtr(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new OwnPtr(ptr); return 0; } if (Config::IsMember(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new Member(ptr); return 0; } if (Config::IsWeakMember(info->name()) && info->GetTemplateArgs(1, &args)) { if (Edge* ptr = CreateEdge(args[0])) return new WeakMember(ptr); return 0; } if (Config::IsPersistent(info->name())) { // Persistent might refer to v8::Persistent, so check the name space. // TODO: Consider using a more canonical identification than names. NamespaceDecl* ns = dyn_cast<NamespaceDecl>(info->record()->getDeclContext()); if (!ns || ns->getName() != "WebCore") return 0; if (!info->GetTemplateArgs(1, &args)) return 0; if (Edge* ptr = CreateEdge(args[0])) return new Persistent(ptr); return 0; } if (Config::IsGCCollection(info->name()) || Config::IsWTFCollection(info->name())) { bool is_root = Config::IsPersistentGCCollection(info->name()); bool on_heap = is_root || info->IsHeapAllocatedCollection(); size_t count = Config::CollectionDimension(info->name()); if (!info->GetTemplateArgs(count, &args)) return 0; Collection* edge = new Collection(info, on_heap, is_root); for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { if (Edge* member = CreateEdge(*it)) { edge->members().push_back(member); } else { // We failed to create an edge so abort the entire edge construction. delete edge; // Will delete the already allocated members. return 0; } } return edge; } return new Value(info); }
NamespaceDecl *Sema::ActOnRogerNamespaceHeaderPart(DeclContext *DeclContext, IdentifierInfo *II, SourceLocation IdentLoc, AttributeList *AttrList) { // set CurContext SourceLocation NamespaceLoc; SourceLocation InlineLoc; SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; assert(II); SourceLocation Loc = IdentLoc; bool IsInline = false; bool IsInvalid = false; bool IsStd = false; bool AddToKnown = false; //Scope *DeclRegionScope = NamespcScope->getParent(); NamespaceDecl *PrevNS = 0; // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not // have been previously defined in the declarative region in // which the original-namespace-definition appears. The // identifier in an original-namespace-definition is the name of // the namespace. Subsequently in that declarative region, it is // treated as an original-namespace-name. // // Since namespace names are unique in their scope, and we don't // look through using directives, just look for any ordinary names. const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | Decl::IDNS_Namespace; NamedDecl *PrevDecl = 0; DeclContext::lookup_result R = DeclContext->getRedeclContext()->lookup(II); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { if ((*I)->getIdentifierNamespace() & IDNS) { PrevDecl = *I; break; } } PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl); if (PrevNS) { // This is an extended namespace definition. if (IsInline != PrevNS->isInline()) { // DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II, // &IsInline, PrevNS); assert(false && "need to implement this"); } return PrevNS; } else if (PrevDecl) { // This is an invalid name redefinition. Diag(Loc, diag::err_redefinition_different_kind) << II; Diag(PrevDecl->getLocation(), diag::note_previous_definition); IsInvalid = true; // Continue on to push Namespc as current DeclContext and return it. } else if (II->isStr("std") && DeclContext->getRedeclContext()->isTranslationUnit()) { // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. PrevNS = getStdNamespace(); IsStd = true; AddToKnown = !IsInline; } else { // We've seen this namespace for the first time. AddToKnown = !IsInline; } NamespaceDecl *Namespc = NamespaceDecl::Create(Context, DeclContext, IsInline, StartLoc, Loc, II, PrevNS); Namespc->IsRogerNamespace = true; if (IsInvalid) Namespc->setInvalidDecl(); //ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); // FIXME: Should we be merging attributes? if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>()) PushNamespaceVisibilityAttr(Attr, Loc); if (IsStd) StdNamespace = Namespc; if (AddToKnown) KnownNamespaces[Namespc] = false; DeclContext->addDecl(Namespc); if (PrevNS) { return PrevNS; } else { return Namespc; } }
// N-pass system. // there's no point counting at this stage. static void codegenTopLevel(CodegenInstance* cgi, int pass, std::deque<Expr*> expressions, bool isInsideNamespace) { if(pass == 0) { // add all the types for order-independence -- if we encounter a need, we can // force codegen. for(Expr* e : expressions) { NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); TypeAlias* ta = dynamic_cast<TypeAlias*>(e); Struct* str = dynamic_cast<Struct*>(e); Class* cls = dynamic_cast<Class*>(e); // enum : class, extension : class Func* fn = dynamic_cast<Func*>(e); ForeignFuncDecl* ffi = dynamic_cast<ForeignFuncDecl*>(e); OpOverload* oo = dynamic_cast<OpOverload*>(e); if(ns) ns->codegenPass(cgi, pass); else if(ta) addTypeToFuncTree(cgi, ta, ta->name, TypeKind::TypeAlias); else if(str) addTypeToFuncTree(cgi, str, str->name, TypeKind::Struct); else if(cls) addTypeToFuncTree(cgi, cls, cls->name, TypeKind::Class); else if(fn) addFuncDeclToFuncTree(cgi, fn->decl); else if(ffi) addFuncDeclToFuncTree(cgi, ffi->decl); else if(oo) addOpOverloadToFuncTree(cgi, oo); } } else if(pass == 1) { // pass 1: setup extensions for(Expr* e : expressions) { Extension* ext = dynamic_cast<Extension*>(e); NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); if(ext) ext->mangledName = cgi->mangleWithNamespace(ext->name); else if(ns) ns->codegenPass(cgi, pass); } // we need the 'Type' enum to be available, as well as the 'Any' type, // before any variables are encountered. if(!isInsideNamespace) TypeInfo::initialiseTypeInfo(cgi); } else if(pass == 2) { // pass 2: create types for(Expr* e : expressions) { Struct* str = dynamic_cast<Struct*>(e); Class* cls = dynamic_cast<Class*>(e); // enums are handled, since enum : class NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); if(str) str->createType(cgi); if(cls) cls->createType(cgi); else if(ns) ns->codegenPass(cgi, pass); } } else if(pass == 3) { // pass 3: override types with any extensions for(Expr* e : expressions) { Extension* ext = dynamic_cast<Extension*>(e); NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); TypeAlias* ta = dynamic_cast<TypeAlias*>(e); if(ext) ext->createType(cgi); else if(ta) ta->createType(cgi); else if(ns) ns->codegenPass(cgi, pass); } // step 3: generate the type info. // now that we have all the types that we need, and they're all fully // processed, we create the Type enum. TypeInfo::generateTypeInfo(cgi); } else if(pass == 4) { // pass 4: create declarations for(Expr* e : expressions) { ForeignFuncDecl* ffi = dynamic_cast<ForeignFuncDecl*>(e); Func* func = dynamic_cast<Func*>(e); NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); if(ffi) ffi->codegen(cgi); else if(ns) ns->codegenPass(cgi, pass); else if(func) { // func->decl->codegen(cgi); } } } else if(pass == 5) { // start semantic analysis before any typechecking needs to happen. SemAnalysis::rewriteDotOperators(cgi); // pass 4: everything else for(Expr* e : expressions) { Struct* str = dynamic_cast<Struct*>(e); Class* cls = dynamic_cast<Class*>(e); // again, enums are handled since enum : class Extension* ext = dynamic_cast<Extension*>(e); NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); VarDecl* vd = dynamic_cast<VarDecl*>(e); if(str) str->codegen(cgi); else if(cls) cls->codegen(cgi); else if(ext) ext->codegen(cgi); else if(ns) ns->codegenPass(cgi, pass); else if(vd) vd->isGlobal = true, vd->codegen(cgi); } } else if(pass == 6) { // pass 7: functions. for generic shit. for(Expr* e : expressions) { Func* func = dynamic_cast<Func*>(e); NamespaceDecl* ns = dynamic_cast<NamespaceDecl*>(e); if(func && !func->didCodegen) func->codegen(cgi); if(ns) ns->codegenPass(cgi, pass); } } else { error("Invalid pass number '%d'\n", pass); } }
TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) { auto Decls = makeDecls<ClassTemplateSpecializationDecl>( R"(template <class T> struct foo; template<> struct foo<int>{};)", R"(template <class T> struct foo; template<> struct foo<signed int>{};)", Lang_CXX, classTemplateSpecializationDecl()); auto Spec0 = get<0>(Decls); auto Spec1 = get<1>(Decls); EXPECT_TRUE(testStructuralMatch(Spec0, Spec1)); } TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) { auto Decls = makeDecls<ClassTemplateSpecializationDecl>( R"(template <class T> struct foo; template<> struct foo<char>{};)", R"(template <class T> struct foo; template<> struct foo<signed char>{};)", Lang_CXX, classTemplateSpecializationDecl()); auto Spec0 = get<0>(Decls); auto Spec1 = get<1>(Decls); EXPECT_FALSE(testStructuralMatch(Spec0, Spec1)); } TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) { auto Decls = makeDecls<ClassTemplateSpecializationDecl>( R"( struct true_type{}; template <class T> struct foo; template<> struct foo<char> : true_type {}; )", R"( struct true_type{}; template <class T> struct foo; template<> struct foo<signed char> : true_type {}; )", Lang_CXX, classTemplateSpecializationDecl()); EXPECT_FALSE(testStructuralMatch(Decls)); } // This test is disabled for now. // FIXME Enable it, once the check is implemented. TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) { auto Code = R"( namespace NS { template <class T> class Base { int a; }; class Derived : Base<Derived> { }; } void foo(NS::Derived &); )"; auto Decls = makeNamedDecls(Code, Code, Lang_CXX); NamespaceDecl *NS = LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl()); ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match( get<1>(Decls), classTemplateDecl(hasName("Base"))); // Reorder the decls, move the TD to the last place in the DC. NS->removeDecl(TD); NS->addDeclInternal(TD); EXPECT_FALSE(testStructuralMatch(Decls)); }