void PHPCodeCompletion::DoShowCompletionBox(const PHPEntityBase::List_t& entries, PHPExpression::Ptr_t expr) { std::vector<TagEntryPtr> tags; wxStringSet_t uniqueEntries; // search for the old item PHPEntityBase::List_t::const_iterator iter = entries.begin(); for(; iter != entries.end(); ++iter) { PHPEntityBase::Ptr_t entry = *iter; if(uniqueEntries.count(entry->GetFullName()) == 0) { uniqueEntries.insert(entry->GetFullName()); } else { // don't add duplicate entries continue; } PHPEntityBase::Ptr_t ns = expr->GetSourceFile()->Namespace(); // the namespace at the source file TagEntryPtr t = DoPHPEntityToTagEntry(entry); t->SetUserData(new PHPCCUserData(entry)); tags.push_back(t); } if(tags.empty()) return; std::sort(tags.begin(), tags.end(), _SAscendingSort()); m_manager->GetActiveEditor()->ShowCompletionBox(tags, expr->GetFilter(), false, this); }
void PHPCodeCompletion::DoShowCompletionBox(const PHPEntityBase::List_t& entries, PHPExpression::Ptr_t expr) { wxCodeCompletionBoxEntry::Vec_t ccEntries; TagEntryPtrVector_t tags; wxStringSet_t uniqueEntries; // search for the old item PHPEntityBase::List_t::const_iterator iter = entries.begin(); for(; iter != entries.end(); ++iter) { PHPEntityBase::Ptr_t entry = *iter; if(uniqueEntries.count(entry->GetFullName()) == 0) { uniqueEntries.insert(entry->GetFullName()); } else { // don't add duplicate entries continue; } PHPEntityBase::Ptr_t ns = expr->GetSourceFile()->Namespace(); // the namespace at the source file TagEntryPtr t = DoPHPEntityToTagEntry(entry); tags.push_back(t); } std::sort(tags.begin(), tags.end(), _SAscendingSort()); for(size_t i = 0; i < tags.size(); ++i) { wxCodeCompletionBoxEntry::Ptr_t ccEntry = wxCodeCompletionBox::TagToEntry(tags.at(i)); ccEntry->SetComment(tags.at(i)->GetComment()); ccEntries.push_back(ccEntry); } wxCodeCompletionBoxManager::Get().ShowCompletionBox( m_manager->GetActiveEditor()->GetCtrl(), ccEntries, wxCodeCompletionBox::kRefreshOnKeyType, wxNOT_FOUND); }
void PHPEditorContextMenu::OnInsertDoxyComment(wxCommandEvent& e) { IEditor* editor = m_manager->GetActiveEditor(); if(editor) { PHPEntityBase::Ptr_t entry = PHPCodeCompletion::Instance()->GetPHPEntityAtPos(editor, editor->GetCurrentPosition()); if(entry) { wxStyledTextCtrl* ctrl = editor->GetCtrl(); ctrl->BeginUndoAction(); wxString comment = entry->FormatPhpDoc(); // Create the whitespace buffer int lineStartPos = ctrl->PositionFromLine(ctrl->GetCurrentLine()); int lineEndPos = lineStartPos + ctrl->LineLength(ctrl->GetCurrentLine()); // Collect all whitespace from the begining of the line until the first non whitespace // character we find wxString whitespace; for(int i = lineStartPos; lineStartPos < lineEndPos; ++i) { if(ctrl->GetCharAt(i) == ' ' || ctrl->GetCharAt(i) == '\t') { whitespace << (wxChar)ctrl->GetCharAt(i); } else { break; } } // Prepare the comment block wxArrayString lines = ::wxStringTokenize(comment, "\n", wxTOKEN_STRTOK); for(size_t i = 0; i < lines.size(); ++i) { lines.Item(i).Prepend(whitespace); } // Glue the lines back together wxString doxyBlock = ::wxJoin(lines, '\n'); doxyBlock << "\n"; // Insert the text ctrl->InsertText(lineStartPos, doxyBlock); // Try to place the caret after the @brief wxRegEx reBrief("[@\\]brief[ \t]*"); if(reBrief.IsValid() && reBrief.Matches(doxyBlock)) { wxString match = reBrief.GetMatch(doxyBlock); // Get the index int where = doxyBlock.Find(match); if(where != wxNOT_FOUND) { where += match.length(); int caretPos = lineStartPos + where; editor->SetCaretAt(caretPos); // Remove the @brief as its non standard in the PHP world editor->GetCtrl()->DeleteRange(caretPos - match.length(), match.length()); } } editor->GetCtrl()->EndUndoAction(); } } }
void PHPCodeCompletion::DoOpenEditorForEntry(PHPEntityBase::Ptr_t entry) { // Open the file (make sure we use the 'OpenFile' so we will get a browsing record) IEditor* editor = m_manager->OpenFile(entry->GetFilename().GetFullPath(), wxEmptyString, entry->GetLine()); if(editor) { // Select the word in the editor (its a new one) int selectFromPos = editor->GetCtrl()->PositionFromLine(entry->GetLine()); DoSelectInEditor(editor, entry->GetShortName(), selectFromPos); } }
PHPSetterGetterEntry::Vec_t PHPRefactoring::GetGetters(IEditor* editor) const { PHPSetterGetterEntry::Vec_t getters, candidates; if(!editor) { return getters; } // Parse until the current position wxString text = editor->GetTextRange(0, editor->GetCurrentPosition()); PHPSourceFile sourceFile(text); sourceFile.SetParseFunctionBody(true); sourceFile.SetFilename(editor->GetFileName()); sourceFile.Parse(); const PHPEntityClass* scopeAtPoint = sourceFile.Class()->Cast<PHPEntityClass>(); if(!scopeAtPoint) { return getters; } // filter out const PHPEntityBase::List_t& children = scopeAtPoint->GetChildren(); PHPEntityBase::List_t::const_iterator iter = children.begin(); PHPEntityBase::List_t members, functions; for(; iter != children.end(); ++iter) { PHPEntityBase::Ptr_t child = *iter; if(child->Is(kEntityTypeFunction)) { functions.push_back(child); } else if(child->Is(kEntityTypeVariable) && child->Cast<PHPEntityVariable>()->IsMember() && !child->Cast<PHPEntityVariable>()->IsConst() && !child->Cast<PHPEntityVariable>()->IsStatic()) { // a member of a class members.push_back(child); } } if(members.empty()) { return getters; } // Prepare list of candidates PHPEntityBase::List_t::iterator membersIter = members.begin(); for(; membersIter != members.end(); ++membersIter) { PHPSetterGetterEntry candidate(*membersIter); // make sure we don't add setters that already exist if(FindByName(functions, candidate.GetGetter(kSG_NameOnly))) { continue; } candidates.push_back(candidate); } getters.swap(candidates); return getters; }
const PHPEntityBase* PHPSourceFile::Class() { PHPEntityBase::Ptr_t curScope = CurrentScope(); PHPEntityBase* pScope = curScope.Get(); while(pScope) { PHPEntityClass* cls = pScope->Cast<PHPEntityClass>(); if(cls) { // this scope is a class return pScope; } pScope = pScope->Parent(); } return NULL; }
void PHPFileLayoutTree::BuildTree(wxTreeItemId parentTreeItem, PHPEntityBase::Ptr_t entity) { int imgID = GetImageId(entity); wxTreeItemId parent = AppendItem(parentTreeItem, entity->GetDisplayName(), imgID, imgID, new QItemData(entity)); // dont add the children of the function (i.e. function arguments) if(entity->Is(kEntityTypeFunction)) return; const PHPEntityBase::List_t& children = entity->GetChildren(); if(!children.empty()) { PHPEntityBase::List_t::const_iterator iter = children.begin(); for(; iter != children.end(); ++iter) { BuildTree(parent, *iter); } } }
PHPLocation::Ptr_t PHPCodeCompletion::FindDefinition(IEditor* editor, int pos) { CHECK_PHP_WORKSPACE_RET_NULL(); PHPLocation::Ptr_t loc; // Null if(IsPHPFile(editor)) { PHPEntityBase::Ptr_t resolved = GetPHPEntryUnderTheAtPos(editor, editor->GetCurrentPosition()); if(resolved) { loc = new PHPLocation; loc->filename = resolved->GetFilename().GetFullPath(); loc->linenumber = resolved->GetLine(); loc->what = resolved->GetShortName(); } } return loc; }
void PHPCodeCompletion::GetMembers(IEditor* editor, PHPEntityBase::List_t& members, wxString& scope) { members.clear(); scope.clear(); if(!editor) { return; } // Parse until the current position to get the current scope name { wxString text = editor->GetTextRange(0, editor->GetCurrentPosition()); PHPSourceFile sourceFile(text); sourceFile.SetParseFunctionBody(true); sourceFile.SetFilename(editor->GetFileName()); sourceFile.Parse(); const PHPEntityClass* scopeAtPoint = sourceFile.Class()->Cast<PHPEntityClass>(); if(!scopeAtPoint) { return; } scope = scopeAtPoint->GetFullName(); } // Second parse: parse the entire buffer so we are not limited by the caret position wxString text = editor->GetTextRange(0, editor->GetLength()); PHPSourceFile sourceFile(text); sourceFile.SetParseFunctionBody(true); sourceFile.SetFilename(editor->GetFileName()); sourceFile.Parse(); // Locate the scope PHPEntityBase::Ptr_t parentClass = sourceFile.Namespace()->FindChild(scope); if(!parentClass) return; // filter out const PHPEntityBase::List_t& children = parentClass->GetChildren(); PHPEntityBase::List_t::const_iterator iter = children.begin(); for(; iter != children.end(); ++iter) { PHPEntityBase::Ptr_t child = *iter; if(child->Is(kEntityTypeVariable) && child->Cast<PHPEntityVariable>()->IsMember() && !child->Cast<PHPEntityVariable>()->IsConst() && !child->Cast<PHPEntityVariable>()->IsStatic()) { // a member of a class members.push_back(child); } } }
void PHPCodeCompletion::OnFindSymbol(clCodeCompletionEvent& e) { if(PHPWorkspace::Get()->IsOpen()) { if(!CanCodeComplete(e)) return; IEditor* editor = dynamic_cast<IEditor*>(e.GetEditor()); if(editor) { PHPEntityBase::Ptr_t resolved = GetPHPEntryUnderTheAtPos(editor, editor->GetCurrentPosition()); if(resolved) { m_manager->OpenFile(resolved->GetFilename().GetFullPath(), "", resolved->GetLine()); } } } else { e.Skip(); } }
int PHPOutlineTree::GetImageId(PHPEntityBase::Ptr_t entry) { BitmapLoader* bmpLoader = clGetManager()->GetStdIcons(); if(entry->Is(kEntityTypeFunction)) { PHPEntityFunction* func = entry->Cast<PHPEntityFunction>(); if(func->HasFlag(kFunc_Private)) return bmpLoader->GetImageIndex(BitmapLoader::kFunctionPrivate); else if(func->HasFlag(kFunc_Protected)) return bmpLoader->GetImageIndex(BitmapLoader::kFunctionProtected); else // public return bmpLoader->GetImageIndex(BitmapLoader::kFunctionPublic); } else if(entry->Is(kEntityTypeVariable)) { PHPEntityVariable* var = entry->Cast<PHPEntityVariable>(); if(!var->IsMember() && !var->IsConst()) { // A global variale return bmpLoader->GetImageIndex(BitmapLoader::kMemberPublic); } else if(var->IsMember()) { if(var->HasFlag(kVar_Const)) return bmpLoader->GetImageIndex(BitmapLoader::kConstant); // constant // Member if(var->HasFlag(kVar_Private)) return bmpLoader->GetImageIndex(BitmapLoader::kMemberPrivate); else if(var->HasFlag(kVar_Protected)) return bmpLoader->GetImageIndex(BitmapLoader::kMemberProtected); else return bmpLoader->GetImageIndex(BitmapLoader::kMemberPublic); } else if(var->IsConst()) { // Constant return bmpLoader->GetImageIndex(BitmapLoader::kConstant); } else { return bmpLoader->GetImageIndex(BitmapLoader::kMemberPublic); } } else if(entry->Is(kEntityTypeNamespace)) { // Namespace return bmpLoader->GetImageIndex(BitmapLoader::kNamespace); } else if(entry->Is(kEntityTypeClass)) { return bmpLoader->GetImageIndex(BitmapLoader::kClass); } return wxNOT_FOUND; // Unknown }
int PHPFileLayoutTree::GetImageId(PHPEntityBase::Ptr_t entry) { if(entry->Is(kEntityTypeFunction)) { PHPEntityFunction* func = entry->Cast<PHPEntityFunction>(); if(func->HasFlag(kFunc_Private)) return 1; else if(func->HasFlag(kFunc_Protected)) return 2; else // public return 3; } else if(entry->Is(kEntityTypeVariable)) { PHPEntityVariable* var = entry->Cast<PHPEntityVariable>(); if(!var->IsMember() && !var->IsConst()) { // A global variale return 6; } else if(var->IsMember()) { if(var->HasFlag(kVar_Const)) return 9; // constant // Member if(var->HasFlag(kVar_Private)) return 4; else if(var->HasFlag(kVar_Protected)) return 5; else return 6; } else if(var->IsConst()) { // Constant return 9; } else { return 6; } } else if(entry->Is(kEntityTypeNamespace)) { // Namespace return 7; } else if(entry->Is(kEntityTypeClass)) { return 8; } return -1; // Unknown }
PHPLocation::Ptr_t PHPCodeCompletion::FindDefinition(IEditor* editor, int pos) { CHECK_PHP_WORKSPACE_RET_NULL(); PHPLocation::Ptr_t loc; // Null if(IsPHPFile(editor)) { PHPEntityBase::Ptr_t resolved = GetPHPEntityAtPos(editor, editor->GetCurrentPosition()); if(resolved) { if(resolved->Is(kEntityTypeFunctionAlias)) { // use the internal function resolved = resolved->Cast<PHPEntityFunctionAlias>()->GetFunc(); } loc = new PHPLocation; loc->filename = resolved->GetFilename().GetFullPath(); loc->linenumber = resolved->GetLine(); loc->what = resolved->GetShortName(); } } return loc; }
void PHPCodeCompletion::OnTypeinfoTip(clCodeCompletionEvent& e) { if(PHPWorkspace::Get()->IsOpen()) { if(!CanCodeComplete(e)) return; IEditor* editor = dynamic_cast<IEditor*>(e.GetEditor()); if(editor) { if(IsPHPFile(editor)) { PHPEntityBase::Ptr_t entity = GetPHPEntityAtPos(editor, e.GetPosition()); if(entity) { e.SetTooltip(entity->ToTooltip()); } return; } } } else { e.Skip(); } }
void PHPSourceFile::OnConstant(const phpLexerToken& tok) { // Parse constant line (possibly multiple constants) phpLexerToken token; PHPEntityBase::Ptr_t member; while(NextToken(token)) { if(token.type == ';') { if(member) { CurrentScope()->AddChild(member); break; } } else if(token.type == ',') { if(member) { CurrentScope()->AddChild(member); member.Reset(NULL); } } else if(token.type == kPHP_T_IDENTIFIER) { // found the constant name member.Reset(new PHPEntityVariable()); member->Cast<PHPEntityVariable>()->SetFlag(kVar_Const); member->Cast<PHPEntityVariable>()->SetFlag(kVar_Member); member->SetFullName(token.text); member->SetLine(token.lineNumber); member->SetFilename(m_filename.GetFullPath()); } else { // do nothing } } }
void OpenResourceDlg::DoGetResources(const wxString& filter) { m_resources.clear(); PHPEntityBase::List_t matches; m_table.LoadAllByFilter(matches, filter); // Convert the PHP matches into resources PHPEntityBase::List_t::iterator iter = matches.begin(); m_resources.reserve(matches.size()); for(; iter != matches.end(); ++iter) { PHPEntityBase::Ptr_t match = *iter; if(FileUtils::FuzzyMatch(filter, match->GetFullName())) { ResourceItem resource; resource.displayName = match->GetDisplayName(); resource.filename = match->GetFilename(); resource.line = match->GetLine(); resource.SetType(match); m_resources.push_back(resource); } } }
bool PHPExpression::FixReturnValueNamespace(PHPLookupTable& lookup, PHPEntityBase::Ptr_t parent, const wxString& classFullpath, wxString& fixedpath) { if(!parent) return false; PHPEntityBase::Ptr_t pClass = lookup.FindClass(classFullpath); if(!pClass) { // classFullpath does not exist // prepend the parent namespace to its path and check again wxString parentNamespace = parent->GetFullName().BeforeLast('\\'); wxString returnValueNamespace = classFullpath.BeforeLast('\\'); wxString returnValueName = classFullpath.AfterLast('\\'); wxString newType = PHPEntityNamespace::BuildNamespace(parentNamespace, returnValueNamespace); newType << "\\" << returnValueName; pClass = lookup.FindClass(newType); if(pClass) { fixedpath = newType; return true; } } return false; }
void PHPCodeCompletion::OnInsertDoxyBlock(clCodeCompletionEvent& e) { e.Skip(); // Do we have a workspace open? CHECK_COND_RET(PHPWorkspace::Get()->IsOpen()); // Sanity IEditor* editor = dynamic_cast<IEditor*>(e.GetEditor()); CHECK_PTR_RET(editor); // Is this a PHP editor? CHECK_COND_RET(IsPHPFile(editor)); // Get the text from the caret current position // until the end of file wxString unsavedBuffer = editor->GetTextRange(editor->GetCurrentPosition(), editor->GetLength()); unsavedBuffer.Trim().Trim(false); PHPSourceFile source("<?php " + unsavedBuffer); source.SetParseFunctionBody(false); source.Parse(); PHPEntityBase::Ptr_t ns = source.Namespace(); if(ns) { const PHPEntityBase::List_t& children = ns->GetChildren(); for(PHPEntityBase::List_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) { PHPEntityBase::Ptr_t match = *iter; if(match->GetLine() == 0 && match->Is(kEntityTypeFunction)) { e.Skip(false); // notify codelite to stop processing this event wxString phpdoc = match->FormatPhpDoc(); phpdoc.Trim(); e.SetTooltip(phpdoc); } } } }
PHPEntityBase::Ptr_t PHPCodeCompletion::DoGetPHPEntryUnderTheAtPos(IEditor* editor, int pos, bool forFunctionCalltip) { if(!PHPWorkspace::Get()->IsOpen()) return PHPEntityBase::Ptr_t(NULL); pos = editor->GetCtrl()->WordEndPosition(pos, true); // Get the expression under the caret wxString unsavedBuffer = editor->GetTextRange(0, pos); wxString filter; PHPEntityBase::Ptr_t resolved; // Parse the source file PHPSourceFile source(unsavedBuffer); source.SetFilename(editor->GetFileName()); source.SetParseFunctionBody(false); source.Parse(); PHPEntityBase::Ptr_t currentScope = source.CurrentScope(); if(currentScope && currentScope->Is(kEntityTypeClass)) { // we are trying to resolve a 'word' under the caret within the class // body but _not_ within a function body (i.e. it can only be // a definition of some kind) // try to construct an expression that will work int wordStart = editor->GetCtrl()->WordStartPosition(pos, true); wxString theWord = editor->GetTextRange(wordStart, pos); wxString theWordNoDollar = theWord; if(theWord.StartsWith("$")) { theWordNoDollar = theWord.Mid(1); } PHPExpression expr2(unsavedBuffer, "<?php $this->" + theWordNoDollar, forFunctionCalltip); resolved = expr2.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr2.GetFilter(); if(!resolved) { // Maybe its a static member/function/const, try using static keyword PHPExpression expr3(unsavedBuffer, "<?php static::" + theWord, forFunctionCalltip); resolved = expr2.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr2.GetFilter(); } } if(!resolved) { PHPExpression expr(unsavedBuffer, "", forFunctionCalltip); resolved = expr.Resolve(m_lookupTable, editor->GetFileName().GetFullPath()); filter = expr.GetFilter(); } if(resolved && !filter.IsEmpty()) { resolved = m_lookupTable.FindMemberOf(resolved->GetDbId(), filter); if(!resolved) { // Fallback to functions and constants PHPEntityBase::List_t children = m_lookupTable.FindGlobalFunctionAndConsts(PHPLookupTable::kLookupFlags_ExactMatch, filter); if(children.size() == 1) { resolved = *children.begin(); } } if(resolved && resolved->Is(kEntityTypeFunction)) { // for a function, we need to load its children (function arguments) resolved->SetChildren(m_lookupTable.LoadFunctionArguments(resolved->GetDbId())); } else if(resolved && resolved->Is(kEntityTypeFunctionAlias)) { // for a function alias, we need to load the actual functions' children (function arguments) PHPEntityBase::Ptr_t realFunc = resolved->Cast<PHPEntityFunctionAlias>()->GetFunc(); realFunc->SetChildren(m_lookupTable.LoadFunctionArguments(realFunc->GetDbId())); } } return resolved; }
TagEntryPtr PHPCodeCompletion::DoPHPEntityToTagEntry(PHPEntityBase::Ptr_t entry) { TagEntryPtr t(new TagEntry()); // wxString name = entry->Is(kEntityTypeNamespace) ? entry->GetFullName() : entry->GetShortName(); wxString name = entry->GetShortName(); if(entry->Is(kEntityTypeVariable) && entry->Cast<PHPEntityVariable>()->IsMember() && name.StartsWith(wxT("$")) && !entry->Cast<PHPEntityVariable>()->IsStatic()) { name.Remove(0, 1); } else if((entry->Is(kEntityTypeClass) || entry->Is(kEntityTypeNamespace)) && name.StartsWith("\\")) { name.Remove(0, 1); } t->SetName(name); t->SetParent(entry->Parent() ? entry->Parent()->GetFullName() : ""); t->SetPattern(t->GetName()); // Set the document comment wxString comment, docComment; docComment = entry->GetDocComment(); if(docComment.IsEmpty() == false) { docComment.Trim().Trim(false); // The Doc comment comment << docComment << wxT("\n<hr>"); // HLine } wxFileName fn(entry->GetFilename()); fn.MakeRelativeTo(PHPWorkspace::Get()->GetFilename().GetPath()); comment << fn.GetFullName() << wxT(" : ") << entry->GetLine(); t->SetComment(comment); // Access if(entry->Is(kEntityTypeVariable)) { PHPEntityVariable* var = entry->Cast<PHPEntityVariable>(); // visibility if(var->IsPrivate()) t->SetAccess(wxT("private")); else if(var->IsProtected()) t->SetAccess(wxT("protected")); else t->SetAccess(wxT("public")); // type (affects icon) if(var->IsConst() || var->IsDefine()) { t->SetKind("macro"); } else { t->SetKind("variable"); } t->SetReturnValue(""); } else if(entry->Is(kEntityTypeFunction) || entry->Is(kEntityTypeFunctionAlias)) { PHPEntityFunction* func = NULL; if(entry->Is(kEntityTypeFunctionAlias)) { func = entry->Cast<PHPEntityFunctionAlias>()->GetFunc()->Cast<PHPEntityFunction>(); } else { func = entry->Cast<PHPEntityFunction>(); } if(func->HasFlag(kFunc_Private)) { t->SetAccess(wxT("private")); } else if(func->HasFlag(kFunc_Protected)) { t->SetAccess("protected"); } else { t->SetAccess(wxT("public")); } t->SetSignature(func->GetSignature()); t->SetPattern(func->GetShortName() + func->GetSignature()); t->SetKind("function"); } else if(entry->Is(kEntityTypeClass)) { t->SetAccess(wxT("public")); t->SetKind("class"); } else if(entry->Is(kEntityTypeNamespace)) { t->SetAccess("public"); t->SetKind("namespace"); } else if(entry->Is(kEntityTypeKeyword)) { t->SetAccess("public"); t->SetKind("cpp_keyword"); } t->SetFlags(TagEntry::Tag_No_Signature_Format); return t; }
TagEntryPtr PHPCodeCompletion::DoPHPEntityToTagEntry(PHPEntityBase::Ptr_t entry) { TagEntryPtr t(new TagEntry()); // wxString name = entry->Is(kEntityTypeNamespace) ? entry->GetFullName() : entry->GetShortName(); wxString name = entry->GetShortName(); if(entry->Is(kEntityTypeVariable) && entry->Cast<PHPEntityVariable>()->IsMember() && name.StartsWith(wxT("$")) && !entry->Cast<PHPEntityVariable>()->IsStatic()) { name.Remove(0, 1); } else if((entry->Is(kEntityTypeClass) || entry->Is(kEntityTypeNamespace)) && name.StartsWith("\\")) { name.Remove(0, 1); } t->SetName(name); t->SetParent(entry->Parent() ? entry->Parent()->GetFullName() : ""); t->SetPattern(t->GetName()); t->SetComment(entry->GetDocComment()); // Access if(entry->Is(kEntityTypeVariable)) { PHPEntityVariable* var = entry->Cast<PHPEntityVariable>(); // visibility if(var->IsPrivate()) t->SetAccess(wxT("private")); else if(var->IsProtected()) t->SetAccess(wxT("protected")); else t->SetAccess(wxT("public")); // type (affects icon) if(var->IsConst() || var->IsDefine()) { t->SetKind("macro"); } else { t->SetKind("variable"); } t->SetReturnValue(""); } else if(entry->Is(kEntityTypeFunction)) { PHPEntityFunction* func = entry->Cast<PHPEntityFunction>(); if(func->HasFlag(kFunc_Private)) { t->SetAccess(wxT("private")); } else if(func->HasFlag(kFunc_Protected)) { t->SetAccess("protected"); } else { t->SetAccess(wxT("public")); } t->SetSignature(func->GetSignature()); t->SetPattern(func->GetShortName() + func->GetSignature()); t->SetKind("function"); } else if(entry->Is(kEntityTypeClass)) { t->SetAccess(wxT("public")); t->SetKind("class"); } else if(entry->Is(kEntityTypeNamespace)) { t->SetAccess("public"); t->SetKind("namespace"); } t->SetFlags(TagEntry::Tag_No_Signature_Format); return t; }
void PHPExpression::Suggest(PHPEntityBase::Ptr_t resolved, PHPLookupTable& lookup, PHPEntityBase::List_t& matches) { // sanity if(!resolved) return; PHPEntityBase::Ptr_t currentScope = GetSourceFile()->CurrentScope(); // GetCount() == 0 && !GetFilter().IsEmpty() i.e. a word completion is required. // We enhance the list with the following: // - PHP keywords // - Global functions // - Global constants // - Function arguments // - Local variables (of the current scope) // - And aliases e.g. 'use foo\bar as Bar;' if(GetCount() == 0 && !GetFilter().IsEmpty()) { // For functions and constants, PHP will fall back to global functions or constants if a // namespaced function or constant does not exist. PHPEntityBase::List_t globals = lookup.FindGlobalFunctionAndConsts(PHPLookupTable::kLookupFlags_Contains, GetFilter()); matches.insert(matches.end(), globals.begin(), globals.end()); if(currentScope && (currentScope->Is(kEntityTypeFunction) || currentScope->Is(kEntityTypeNamespace))) { // If the current scope is a function // add the local variables + function arguments to the current list of matches const PHPEntityBase::List_t& children = currentScope->GetChildren(); PHPEntityBase::List_t::const_iterator iter = children.begin(); for(; iter != children.end(); ++iter) { PHPEntityBase::Ptr_t child = *iter; if(child->Is(kEntityTypeVariable) && child->GetShortName().Contains(GetFilter()) && child->GetShortName() != GetFilter()) { matches.push_back(child); } } } { // Add aliases PHPEntityBase::List_t aliases = GetSourceFile()->GetAliases(); PHPEntityBase::List_t::iterator iter = aliases.begin(); for(; iter != aliases.end(); ++iter) { if((*iter)->GetShortName().Contains(GetFilter())) { matches.push_back(*iter); } } } { // Add $this incase we are inside a class (but only if '$this' contains the filter string) wxString lcFilter = GetFilter().Lower(); if(GetSourceFile()->Class() && wxString("$this").Contains(lcFilter)) { PHPEntityBase::Ptr_t thiz(new PHPEntityVariable()); thiz->SetFullName("$this"); thiz->SetShortName("$this"); thiz->SetFilename(currentScope->GetFilename()); matches.push_back(thiz); } } } // Add the scoped matches // for the code completion size_t flags = PHPLookupTable::kLookupFlags_Contains | GetLookupFlags(); if(resolved->Is(kEntityTypeClass)) { if(resolved->Cast<PHPEntityClass>()->IsInterface() || resolved->Cast<PHPEntityClass>()->IsAbstractClass()) { flags |= PHPLookupTable::kLookupFlags_IncludeAbstractMethods; } } PHPEntityBase::List_t scopeChildren = lookup.FindChildren(resolved->GetDbId(), flags, GetFilter()); matches.insert(matches.end(), scopeChildren.begin(), scopeChildren.end()); // Incase the resolved is a namespace, suggest all children namespaces if(resolved->Is(kEntityTypeNamespace)) { PHPEntityBase::List_t namespaces = lookup.FindNamespaces(resolved->GetFullName(), GetFilter()); matches.insert(matches.end(), namespaces.begin(), namespaces.end()); } // and make the list unique DoMakeUnique(matches); }
wxString PHPExpression::DoSimplifyExpression(int depth, PHPSourceFile::Ptr_t sourceFile) { if(depth > 5 || sourceFile == NULL) { // avoid infinite recursion, by limiting the nest level to 5 return ""; } // Use the provided sourceFile if 'm_sourceFile' is NULL if(!m_sourceFile) { m_sourceFile = sourceFile; } // Parse the input source file PHPEntityBase::Ptr_t scope = sourceFile->CurrentScope(); const PHPEntityBase* innerClass = sourceFile->Class(); // Check the first token // Phase 1: // Loop over the expression and resolve as much as we can here for the first token // (mainly, replace $this, self, static, $variable) phpLexerToken token; wxString newExpr; wxString firstToken; int firstTokenType = wxNOT_FOUND; for(size_t i = 0; i < m_expression.size(); ++i) { token = m_expression.at(i); if(i == 0) { // Perform basic replacements that we can conduct here without the need of the global // lookup table if(token.type == kPHP_T_PARENT) { if(!innerClass) return ""; firstToken = innerClass->GetFullName(); firstTokenType = kPHP_T_PARENT; } else if(token.type == kPHP_T_THIS) { // the first token is $this // replace it with the current class absolute path if(!innerClass) return ""; firstToken = innerClass->GetFullName(); // Is always in absolute path } else if(token.type == kPHP_T_SELF) { // Same as $this: replace it with the current class absolute path if(!innerClass) return ""; firstToken = innerClass->GetFullName(); // Is always in absolute path firstTokenType = kPHP_T_SELF; } else if(token.type == kPHP_T_STATIC) { // Same as $this: replace it with the current class absolute path if(!innerClass) return ""; firstToken = innerClass->GetFullName(); // Is always in absolute path firstTokenType = kPHP_T_STATIC; } else if(token.type == kPHP_T_VARIABLE) { // the expression being evaluated starts with a variable (e.g. $a->something()->) // in this case, use the current scope ('scope') and replace it with the real type // Note that the type can be another expression // e.g.: // $a = $this->getQuery(); // $b = $a->fetchAll()-> // so if the expression being evaluated is "$a->fetchAll()->" // we first replace $a with '$this->getQuery()' so it becomes: // $this->getQuery()->fetchAll()-> // However, $this also need a replacement so eventually, it becomes like this: // \MyClass->getQuery->fetchAll-> and this is something that we can evaluate easily using // our lookup tables (note that the parenthessis are missing on purpose) PHPEntityBase::Ptr_t local = scope->FindChild(token.text); if(local && local->Cast<PHPEntityVariable>()) { if(!local->Cast<PHPEntityVariable>()->GetTypeHint().IsEmpty()) { // we have type hint! - use it firstToken = local->Cast<PHPEntityVariable>()->GetTypeHint(); } else if(!local->Cast<PHPEntityVariable>()->GetExpressionHint().IsEmpty()) { // we have an expression hint - use it // append the "->" to the expression to make sure that the parser will understand it // as an expression PHPExpression e(m_text, local->Cast<PHPEntityVariable>()->GetExpressionHint() + "->"); firstToken = e.DoSimplifyExpression(depth + 1, m_sourceFile); if(firstToken.EndsWith("->")) { // remove the last 2 characters firstToken.RemoveLast(2); } } } else { // this local variable does not exist in the current scope // This is probably a word-completion for local variable m_filter = token.text; return ""; } } else if(token.type == kPHP_T_IDENTIFIER) { // an identifier, convert it to the fullpath firstToken = sourceFile->MakeIdentifierAbsolute(token.text); } } if(!firstToken.IsEmpty()) { newExpr = firstToken; firstToken.Clear(); } else { newExpr << " " << token.text; } } // Phase 2: // Now break the tokens from the lexers into something that we can work with // when using the lookup table. // The split in this phase is done by searching for kPHP_T_OBJECT_OPERATOR and kPHP_T_PAAMAYIM_NEKUDOTAYIM // separators m_expression = CreateExpression("<?php " + newExpr); Part part; wxString currentText; for(size_t i = 0; i < m_expression.size(); ++i) { token = m_expression.at(i); // Remove any braces and split by object kPHP_T_OBJECT_OPERATOR and kPHP_T_PAAMAYIM_NEKUDOTAYIM switch(token.type) { case kPHP_T_OPEN_TAG: break; case '(': if(!currentText.IsEmpty()) { part.m_text = currentText; } break; case ')': // skip it break; case kPHP_T_PAAMAYIM_NEKUDOTAYIM: case kPHP_T_OBJECT_OPERATOR: if(!currentText.IsEmpty() && part.m_text.IsEmpty()) { if(m_parts.empty() && token.type == kPHP_T_PAAMAYIM_NEKUDOTAYIM) { // The first token in the "parts" list has a scope resolving operator ("::") // we need to make sure that the indetifier is provided in fullpath part.m_text = sourceFile->MakeIdentifierAbsolute(currentText); } else { part.m_text = currentText; } } if(m_parts.empty()) { // If the first token before the simplication was 'parent' // keyword, we need to carry this over part.m_textType = firstTokenType; } part.m_operator = token.type; part.m_operatorText = token.text; m_parts.push_back(part); // cleanup currentText.clear(); part.m_text.clear(); part.m_operatorText.clear(); part.m_operator = wxNOT_FOUND; break; case kPHP_T_THIS: case kPHP_T_SELF: case kPHP_T_STATIC: part.m_textType = token.type; currentText << token.text; break; default: currentText << token.text; break; } } if(!currentText.IsEmpty()) { m_filter = currentText; } wxString simplified; List_t::iterator iter = m_parts.begin(); for(; iter != m_parts.end(); ++iter) { simplified << iter->m_text << iter->m_operatorText; } return simplified.Trim().Trim(false); }
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); } } } }