void PHPDocVisitor::OnEntity(PHPEntityBase::Ptr_t entity) { // Locate a comment for this entity entity->SetFilename(m_sourceFile.GetFilename()); if(!entity->GetDocComment().IsEmpty()) { // PHPDoc was already assigned to this entity during the parsing phase if(entity->Is(kEntityTypeClass)) { // Process @property tags here PHPDocComment docComment(m_sourceFile, entity->GetDocComment()); if(!docComment.GetProperties().empty()) { // Got some @properties std::for_each(docComment.GetProperties().begin(), docComment.GetProperties().end(), [&](PHPDocComment::Property::Map_t::value_type& p) { PHPEntityBase::Ptr_t child = entity->FindChild(p.second.name); if(!child) { // No child of this type, create a new property and add it child.Reset(new PHPEntityVariable()); child->SetFilename(m_sourceFile.GetFilename()); child->SetLine(entity->GetLine()); child->Cast<PHPEntityVariable>()->SetTypeHint(p.second.type); child->Cast<PHPEntityVariable>()->SetFlag(kVar_Member); // Member variable child->Cast<PHPEntityVariable>()->SetFlag(kVar_Public); // Public access child->SetShortName(p.second.name); child->SetFullName(p.second.name); entity->AddChild(child); } }); } else if(!docComment.GetMethods().empty()) { std::for_each(docComment.GetMethods().begin(), docComment.GetMethods().end(), [&](PHPEntityBase::Ptr_t method) { entity->AddChild(method); }); } } } else { // search for the comment placed at the top of the variable // this is why we use here -1 int lineNum = (entity->GetLine() - 1); // for debugging purposes wxString entityName = entity->GetShortName(); wxUnusedVar(entityName); std::map<int, phpLexerToken>::iterator iter = m_comments.find(lineNum); if(iter == m_comments.end()) { // try to locate a comment on the same line ++lineNum; iter = m_comments.find(lineNum); } if(iter != m_comments.end()) { // we got a match entity->SetDocComment(iter->second.Text()); m_comments.erase(iter); PHPDocComment docComment(m_sourceFile, entity->GetDocComment()); if(entity->Is(kEntityTypeFunction) && !docComment.GetReturn().IsEmpty()) { entity->Cast<PHPEntityFunction>()->SetReturnValue(docComment.GetReturn()); } else if(entity->Is(kEntityTypeVariable) && !entity->Cast<PHPEntityVariable>()->IsFunctionArg()) { // A global variable, const or a member entity->Cast<PHPEntityVariable>()->SetTypeHint(docComment.GetVar()); } } else if(entity->Is(kEntityTypeVariable) && entity->Parent() && entity->Parent()->Is(kEntityTypeFunction) && entity->Cast<PHPEntityVariable>()->IsFunctionArg()) { // A function argument PHPDocComment docComment(m_sourceFile, entity->Parent()->GetDocComment()); wxString typeHint = docComment.GetParam(entity->GetFullName()); if(!typeHint.IsEmpty()) { entity->Cast<PHPEntityVariable>()->SetTypeHint(typeHint); } } } }
void Func::getFuncInfo(ClassInfo::MethodInfo* mi) const { ASSERT(mi); if (info() != NULL) { // Very large operator=() invocation. *mi = *info(); // Deep copy the vectors of mi-owned pointers. cloneMembers(mi->parameters); cloneMembers(mi->staticVariables); } else { // hphpc and hphpi set the ClassInfo::VariableArguments attribute if the // method contains a call to func_get_arg, func_get_args, or func_num_args. // We don't do this in the VM currently and hopefully we never will need to. int attr = 0; if (m_attrs & AttrReference) attr |= ClassInfo::IsReference; if (m_attrs & AttrAbstract) attr |= ClassInfo::IsAbstract; if (m_attrs & AttrFinal) attr |= ClassInfo::IsFinal; if (m_attrs & AttrProtected) attr |= ClassInfo::IsProtected; if (m_attrs & AttrPrivate) attr |= ClassInfo::IsPrivate; if (m_attrs & AttrStatic) attr |= ClassInfo::IsStatic; if (!(attr & ClassInfo::IsProtected || attr & ClassInfo::IsPrivate)) { attr |= ClassInfo::IsPublic; } if (preClass() && (!strcasecmp(m_name->data(), "__construct") || (!(preClass()->attrs() & AttrTrait) && !strcasecmp(m_name->data(), preClass()->name()->data()) && !preClass()->hasMethod(String("__construct").get())))) { attr |= ClassInfo::IsConstructor; } if (attr == 0) attr = ClassInfo::IsNothing; mi->attribute = (ClassInfo::Attribute)attr; mi->name = m_name->data(); mi->file = m_unit->filepath()->data(); mi->line1 = line1(); mi->line2 = line2(); if (docComment() && !docComment()->empty()) { mi->docComment = docComment()->data(); } // Get the parameter info for (unsigned i = 0; i < unsigned(m_numParams); ++i) { ClassInfo::ParameterInfo* pi = new ClassInfo::ParameterInfo; attr = 0; if (byRef(i)) { attr |= ClassInfo::IsReference; } if (attr == 0) { attr = ClassInfo::IsNothing; } const ParamInfoVec& params = shared()->m_params; const ParamInfo& fpi = params[i]; pi->attribute = (ClassInfo::Attribute)attr; pi->name = shared()->m_localNames[i]->data(); if (params.size() <= i || !fpi.hasDefaultValue()) { pi->value = NULL; pi->valueText = ""; } else { if (fpi.hasScalarDefaultValue()) { // Most of the time the default value is scalar, so we can // avoid evaling in the common case pi->value = strdup(f_serialize( tvAsVariant((TypedValue*)&fpi.defaultValue())).get()->data()); } else { // Eval PHP code to get default value, and serialize the result. Note // that access of undefined class constants can cause the eval() to // fatal. Zend lets such fatals propagate, so don't bother catching // exceptions here. CVarRef v = g_vmContext->getEvaledArg(fpi.phpCode()); pi->value = strdup(f_serialize(v).get()->data()); } // This is a raw char*, but its lifetime should be at least as long // as the the Func*. At this writing, it's a merged anon string // owned by ParamInfo. pi->valueText = fpi.phpCode()->data(); } pi->type = fpi.typeConstraint().exists() ? fpi.typeConstraint().typeName()->data() : ""; mi->parameters.push_back(pi); } // XXX ConstantInfo is abused to store static variable metadata, and // although ConstantInfo::callbacks provides a mechanism for registering // callbacks, it does not pass enough information through for the callback // functions to know the function context whence the callbacks came. // Furthermore, the callback mechanism isn't employed in a fashion that // would allow repeated introspection to reflect updated values. // Supporting introspection of static variable values will require // different plumbing than currently exists in ConstantInfo. const SVInfoVec& staticVars = shared()->m_staticVars; for (SVInfoVec::const_iterator it = staticVars.begin(); it != staticVars.end(); ++it) { ClassInfo::ConstantInfo* ci = new ClassInfo::ConstantInfo; ci->name = *(String*)(&(*it).name); if ((*it).phpCode != NULL) { ci->valueLen = (*it).phpCode->size(); ci->valueText = (*it).phpCode->data(); } else { ci->valueLen = 0; ci->valueText = ""; } mi->staticVariables.push_back(ci); } } }