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);
    }
}
Beispiel #5
0
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;
}
Beispiel #6
0
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();
    }
}
Beispiel #11
0
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();
    }
}
Beispiel #15
0
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);
        }
    }
}
Beispiel #17
0
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;
}
Beispiel #22
0
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);
}
Beispiel #23
0
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);
            }
        }
    }
}