PHPEntityBase::Ptr_t PHPExpression::Resolve(PHPLookupTable& lookpTable, const wxString& sourceFileName) { if(m_expression.empty()) return PHPEntityBase::Ptr_t(NULL); PHPSourceFile source(m_text); source.SetParseFunctionBody(true); source.SetFilename(sourceFileName); source.Parse(); wxString asString = SimplifyExpression(source, 0); // Now, use the lookup table std::list<PHPExpression::Part>::iterator iter = m_parts.begin(); PHPEntityBase::Ptr_t currentToken(NULL); for(; iter != m_parts.end(); ++iter) { if(!currentToken) { // first token currentToken = lookpTable.FindScope(iter->m_text); } else { // load the children of the current token (optionally, filter by the text) currentToken = lookpTable.FindMemberOf(currentToken->GetDbId(), iter->m_text); } if(!currentToken) { // return NULL return currentToken; } } return currentToken; }
void PHPParserThread::ParseFile(PHPParserThreadRequest* request) { wxFileName fnWorkspaceFile(request->workspaceFile); PHPLookupTable lookuptable; lookuptable.Open(fnWorkspaceFile.GetPath()); // Parse the source file PHPSourceFile sourceFile(wxFileName(request->file)); sourceFile.SetParseFunctionBody(false); sourceFile.Parse(); // Save its symbols lookuptable.UpdateSourceFile(sourceFile); }
void PHPParserThread::ParseFiles(PHPParserThreadRequest* request) { wxFileName fnWorkspaceFile(request->workspaceFile); bool isFull = request->requestType == PHPParserThreadRequest::kParseWorkspaceFilesFull; wxUnusedVar(isFull); wxStringSet_t uniqueFilesSet; uniqueFilesSet.insert(request->files.begin(), request->files.end()); // Open the database PHPLookupTable lookuptable; lookuptable.Open(fnWorkspaceFile.GetPath()); for(size_t i = 0; i < request->frameworksPaths.GetCount(); ++i) { if(ms_goingDown) { ms_goingDown = false; return; } wxArrayString frameworkFiles; wxDir::GetAllFiles(request->frameworksPaths.Item(i), &frameworkFiles, "*.php", wxDIR_DIRS | wxDIR_FILES); uniqueFilesSet.insert(frameworkFiles.begin(), frameworkFiles.end()); } // Convert the set back to array wxArrayString allFiles; wxStringSet_t::iterator iter = uniqueFilesSet.begin(); for(; iter != uniqueFilesSet.end(); ++iter) { allFiles.Add(*iter); } // Get list of PHP files under lookuptable.RecreateSymbolsDatabase(allFiles, request->requestType == PHPParserThreadRequest::kParseWorkspaceFilesFull ? PHPLookupTable::kUpdateMode_Full : PHPLookupTable::kUpdateMode_Fast, [&]() { return PHPParserThread::ms_goingDown; }, false); // reset the shutdown flag ms_goingDown = false; }
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 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); }
PHPEntityBase::Ptr_t PHPExpression::Resolve(PHPLookupTable& lookpTable, const wxString& sourceFileName) { if(m_expression.empty()) return PHPEntityBase::Ptr_t(NULL); m_sourceFile.reset(new PHPSourceFile(m_text)); m_sourceFile->SetParseFunctionBody(true); m_sourceFile->SetFilename(sourceFileName); m_sourceFile->Parse(); if(m_expression.size() == 1 && m_expression.at(0).type == kPHP_T_NS_SEPARATOR) { // user typed '\' return lookpTable.FindScope("\\"); } wxString asString = DoSimplifyExpression(0, m_sourceFile); wxUnusedVar(asString); if(m_parts.empty() && !m_filter.IsEmpty()) { // We have no expression, but the user did type something... // Return the parent scope of what the user typed so far if(m_filter.Contains("\\")) { // A namespace separator was found in the filter, break // the filter into 2: // scope + filter wxString scopePart = m_filter.BeforeLast('\\'); if(!scopePart.StartsWith("\\")) { scopePart.Prepend("\\"); } wxString filterPart = m_filter.AfterLast('\\'); // Adjust the filter m_filter.swap(filterPart); // Fix the scope part scopePart = m_sourceFile->MakeIdentifierAbsolute(scopePart); return lookpTable.FindScope(scopePart); } else { // No namespace separator was typed // try to guess: // if the m_filter contains "(" -> user wants a global functions // else we use the current file scope return lookpTable.FindScope(m_sourceFile->Namespace()->GetFullName()); } } // Now, use the lookup table std::list<PHPExpression::Part>::iterator iter = m_parts.begin(); PHPEntityBase::Ptr_t currentToken(NULL); PHPEntityBase::Ptr_t parentToken(NULL); for(; iter != m_parts.end(); ++iter) { Part& part = *iter; if(!currentToken) { // first token // Check locks first if(part.m_text.StartsWith("$") && m_sourceFile->CurrentScope()) { // a variable currentToken = m_sourceFile->CurrentScope()->FindChild(part.m_text); } if(!currentToken) { currentToken = lookpTable.FindScope(part.m_text); if(!currentToken) { // If we are inside a namespace, try prepending the namespace // to the first token if(m_sourceFile->Namespace() && m_sourceFile->Namespace()->GetFullName() != "\\") { // Not the global namespace wxString fullns = PHPEntityNamespace::BuildNamespace(m_sourceFile->Namespace()->GetFullName(), part.m_text); // Check if it exists PHPEntityBase::Ptr_t pGuess = lookpTable.FindScope(fullns); if(pGuess) { currentToken = pGuess; part.m_text = fullns; } else { // Maybe its a global function.. currentToken = lookpTable.FindFunction(part.m_text); } } else { // Maybe its a global function.. currentToken = lookpTable.FindFunction(part.m_text); } } } } else { // load the children of the current token (optionally, filter by the text) currentToken = lookpTable.FindMemberOf(currentToken->GetDbId(), part.m_text); if(currentToken && currentToken->Is(kEntityTypeFunctionAlias)) { // If the member is a function-alias, use the actual function instead currentToken = currentToken->Cast<PHPEntityFunctionAlias>()->GetFunc(); } } // If the current "part" of the expression ends with a scope resolving operator ("::") or // an object operator ("->") we need to resolve the operator to the actual type ( // incase of a functin it will be the return value, and in case of a variable it will be // the type hint) if(currentToken) { if(part.m_operator == kPHP_T_OBJECT_OPERATOR || part.m_operator == kPHP_T_PAAMAYIM_NEKUDOTAYIM) { wxString actualType; if(currentToken->Is(kEntityTypeFunction)) { // return the function return value actualType = currentToken->Cast<PHPEntityFunction>()->GetReturnValue(); } else if(currentToken->Is(kEntityTypeVariable)) { // return the type hint actualType = currentToken->Cast<PHPEntityVariable>()->GetTypeHint(); } wxString fixedpath; if(!actualType.IsEmpty() && FixReturnValueNamespace(lookpTable, parentToken, actualType, fixedpath)) { actualType.swap(fixedpath); } if(!actualType.IsEmpty()) { currentToken = lookpTable.FindScope(actualType); } } } if(!currentToken) { // return NULL return currentToken; } parentToken = currentToken; } return currentToken; }