File: PHPLookupTable.h

package info (click to toggle)
codelite 17.0.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 136,204 kB
  • sloc: cpp: 491,547; ansic: 280,393; php: 10,259; sh: 8,930; lisp: 7,664; vhdl: 6,518; python: 6,020; lex: 4,920; yacc: 3,123; perl: 2,385; javascript: 1,715; cs: 1,193; xml: 1,110; makefile: 804; cobol: 741; sql: 709; ruby: 620; f90: 566; ada: 534; asm: 464; fortran: 350; objc: 289; tcl: 258; java: 157; erlang: 61; pascal: 51; ml: 49; awk: 44; haskell: 36
file content (423 lines) | stat: -rw-r--r-- 14,655 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// Copyright            : (C) 2015 Eran Ifrah
// File name            : PHPLookupTable.h
//
// -------------------------------------------------------------------------
// A
//              _____           _      _     _ _
//             /  __ \         | |    | |   (_) |
//             | /  \/ ___   __| | ___| |    _| |_ ___
//             | |    / _ \ / _  |/ _ \ |   | | __/ _ )
//             | \__/\ (_) | (_| |  __/ |___| | ||  __/
//              \____/\___/ \__,_|\___\_____/_|\__\___|
//
//                                                  F i l e
//
//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

#ifndef PHPLOOKUPTABLE_H
#define PHPLOOKUPTABLE_H

#include "PHPEntityBase.h"
#include "PHPSourceFile.h"
#include "cl_command_event.h"
#include "codelite_exports.h"
#include "event_notifier.h"
#include "file_logger.h"
#include "fileextmanager.h"
#include "fileutils.h"
#include "smart_ptr.h"
#include "wx/wxsqlite3.h"

#include <set>
#include <unordered_set>
#include <vector>
#include <wx/longlong.h>
#include <wx/stopwatch.h>
#include <wx/string.h>
#include <wxStringHash.h>

wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CL, wxPHP_PARSE_STARTED, clParseEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CL, wxPHP_PARSE_ENDED, clParseEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CL, wxPHP_PARSE_PROGRESS, clParseEvent);

enum ePhpScopeType {
    kPhpScopeTypeAny = -1,
    kPhpScopeTypeNamespace = 0,
    kPhpScopeTypeClass = 1,
};

/**
 * @class PHPLookupTable
 * @brief a database lookup class which allows a quick access
 * to all entities parsed in the workspace
 */
class WXDLLIMPEXP_CL PHPLookupTable
{
    wxSQLite3Database m_db;
    wxFileName m_filename;
    size_t m_sizeLimit;
    std::unordered_set<wxString> m_allClasses;

public:
    enum eLookupFlags {
        kLookupFlags_None = 0,
        kLookupFlags_ExactMatch = (1 << 1),
        kLookupFlags_Contains = (1 << 2),
        kLookupFlags_StartsWith = (1 << 3),
        kLookupFlags_Members = (1 << 4),         // Class members
        kLookupFlags_Constants = (1 << 5),       // 'const'
        kLookupFlags_Static = (1 << 6),          // include static members/functions (static::, class_type::)
        kLookupFlags_Self = (1 << 7),            // self::
        kLookupFlags_NameHintIsScope = (1 << 8), // the namehint provided is of a class name. When enabled, the search
                                                 // will try to take "\" into consideration
        kLookupFlags_Parent = (1 << 9),          // Exclude 'this' from the results and return only
                                                 // its parents parent::
        kLookupFlags_FunctionsAndConstsOnly = (1 << 10), // Fetch functions and consts ONLY
        kLookupFlags_IncludeAbstractMethods = (1 << 11), // Include abstract functions in the result set
    };

    enum eUpdateMode {
        kUpdateMode_Fast,
        kUpdateMode_Full,
    };
    typedef SmartPtr<PHPLookupTable> Ptr_t;
    static void DoSplitFullname(const wxString& fullname, wxString& ns, wxString& shortName);

private:
    void EnsureIntegrity(const wxFileName& filename);
    void DoAddNameFilter(wxString& sql, const wxString& nameHint, size_t flags);

    void CreateSchema();
    PHPEntityBase::Ptr_t DoFindMemberOf(wxLongLong parentDbId, const wxString& exactName,
                                        bool parentIsNamespace = false);

    void DoFixVarsDocComment(PHPEntityBase::List_t& matches, wxLongLong parentId);
    void DoGetInheritanceParentIDs(PHPEntityBase::Ptr_t cls, std::vector<wxLongLong>& parents,
                                   std::set<wxLongLong>& parentsVisited, bool excludeSelf);

    /**
     * @brief find namespace by fullname. If it does not exist, add it and return a pointer to it
     */
    PHPEntityBase::Ptr_t CreateNamespaceForDefine(PHPEntityBase::Ptr_t define);

    PHPEntityBase::Ptr_t DoFindScope(const wxString& fullname, ePhpScopeType scopeType = kPhpScopeTypeAny);
    PHPEntityBase::Ptr_t DoFindScope(wxLongLong id, ePhpScopeType scopeType = kPhpScopeTypeAny);
    /**
     * @brief sqlite uses '_' as a wildcard. escape it using '^'
     * as our escape char
     */
    wxString EscapeWildCards(const wxString& str);

    void DoAddLimit(wxString& sql);

    /**
     * @brief allocate new entity that matches the table name
     */
    PHPEntityBase::Ptr_t NewEntity(const wxString& tableName, ePhpScopeType scopeType = kPhpScopeTypeAny);

    /**
     * @brief load entities from table and name hint
     * if nameHint is empty, return empty list
     */
    void LoadFromTableByNameHint(PHPEntityBase::List_t& matches, const wxString& tableName, const wxString& nameHint,
                                 eLookupFlags flags);

    /**
     * @brief use typed: static::
     */
    bool CollectingStatics(size_t flags) const { return (flags & kLookupFlags_Static) || (flags & kLookupFlags_Self); }

    /**
     * @brief return children of parentId _WITHOUT_ taking inheritance into consideration
     */
    void DoFindChildren(PHPEntityBase::List_t& matches, wxLongLong parentId, size_t flags = kLookupFlags_None,
                        const wxString& nameHint = "");

    /**
     * @brief return the timestamp of the last parse for 'filename'
     */
    wxLongLong GetFileLastParsedTimestamp(const wxFileName& filename);

    /**
     * @brief update the file's last updated timestamp
     */
    void UpdateFileLastParsedTimestamp(const wxFileName& filename);

    /**
     * @brief check the database disk image to see if it corrupted
     */
    bool CheckDiskImage(wxSQLite3Database& db, const wxFileName& filename);

public:
    PHPLookupTable();
    virtual ~PHPLookupTable();

    /**
     * @brief rebuild the class cache
     */
    void RebuildClassCache();
    /**
     * @brief return the function closest to a given function and line number
     */
    PHPEntityBase::Ptr_t FindFunctionNearLine(const wxFileName& filename, int lineNumber);

    /**
     * @brief add class name to the class cache
     * @param classname
     */
    void UpdateClassCache(const wxString& classname);

    /**
     * @brief check if a class exists in the cache
     */
    bool ClassExists(const wxString& classname) const;

    void SetSizeLimit(size_t sizeLimit) { this->m_sizeLimit = sizeLimit; }
    /**
     * @brief return the entity at a given file/line
     */
    PHPEntityBase::Ptr_t FindFunctionByLineAndFile(const wxFileName& filename, int line);

    /**
     * @brief return list of functiosn from a given file
     */
    size_t FindFunctionsByFile(const wxFileName& filename, PHPEntityBase::List_t& functions);

    /**
     * @brief open the lookup table database
     */
    void Open(const wxString& workspacePath);

    /**
     * @brief open the symbols database
     */
    void Open(const wxFileName& dbfile);

    /**
     * @brief
     * @return
     */
    bool IsOpened() const;

    /**
     * @brief close the lookup table database
     */
    void Close();

    /**
     * @brief delete the symbols database file from the file system and recreate an empty one
     */
    void ResetDatabase();

    /**
     * @brief clear all cached data from the database
     */
    void ClearAll(bool autoCommit = true);

    /**
     * @brief find a scope symbol (class or namespace) by its fullname
     */
    PHPEntityBase::Ptr_t FindScope(const wxString& fullname);

    /**
     * @brief find a function by its fullname (scope+name)
     */
    PHPEntityBase::Ptr_t FindFunction(const wxString& fullname);

    /**
     * @brief find a class with a given name
     */
    PHPEntityBase::Ptr_t FindClass(const wxString& fullname);

    /**
     * @brief find a class with a given database ID
     */
    PHPEntityBase::Ptr_t FindClass(wxLongLong id);

    /**
     * @brief find a member of parentDbId with name that matches 'exactName'
     */
    PHPEntityBase::Ptr_t FindMemberOf(wxLongLong parentDbId, const wxString& exactName, size_t flags = 0);

    /**
     * @brief find children of a scope by its database ID.
     */
    PHPEntityBase::List_t FindChildren(wxLongLong parentId, size_t flags = kLookupFlags_None,
                                       const wxString& nameHint = "");

    /**
     * @brief find list of symbols with a given name (regardless of the type / scope)
     * a "free style" search
     */
    PHPEntityBase::List_t FindSymbol(const wxString& name);

    /**
     * @brief load the global functions and consts that matches nameHint
     * If nameHint is empty, return an empty list
     */
    PHPEntityBase::List_t FindGlobalFunctionAndConsts(size_t flags = PHPLookupTable::kLookupFlags_Contains,
                                                      const wxString& nameHint = "");

    /**
     * @brief load list of namespaces from the database that
     */
    PHPEntityBase::List_t FindNamespaces(const wxString& fullnameStartsWith, const wxString& shortNameContains = "");
    /**
     * @brief load list of entities from all the tables that matches 'nameHint'
     * if nameHint is empty, return an empty list
     */
    void LoadAllByFilter(PHPEntityBase::List_t& matches, const wxString& nameHint,
                         eLookupFlags flags = kLookupFlags_Contains);
    /**
     * @brief save source file into the database
     */
    void UpdateSourceFile(PHPSourceFile& source, bool autoCommit = true);

    /**
     * @brief update list of source files
     */
    template <typename GoindDownFunc>
    void RecreateSymbolsDatabase(const wxArrayString& files, eUpdateMode updateMode, GoindDownFunc pFuncGoingDown,
                                 bool parseFuncBodies = true);

    /**
     * @brief parse folder
     */
    void ParseFolder(const wxString& folder, const wxString& filemask, eUpdateMode updateMode);

    /**
     * @brief delete all entries belonged to filename.
     * @param filename the file name
     * @param autoCommit when true, issue a begin/commit transcation commands
     */
    void DeleteFileEntries(const wxFileName& filename, bool autoCommit = true);

    /**
     * @brief load function arguments from the database
     * @param parentId the function database ID
     */
    PHPEntityBase::List_t LoadFunctionArguments(wxLongLong parentId);

    /**
     * @brief return reference to the underlying database
     */
    wxSQLite3Database& Database() { return m_db; }
};

template <typename GoindDownFunc>
void PHPLookupTable::RecreateSymbolsDatabase(const wxArrayString& files, eUpdateMode updateMode,
                                             GoindDownFunc pFuncGoingDown, bool parseFuncBodies)
{
    try {

        {
            clParseEvent event(wxPHP_PARSE_STARTED);
            event.SetTotalFiles(files.GetCount());
            event.SetCurfileIndex(0);
            EventNotifier::Get()->AddPendingEvent(event);
        }

        wxStopWatch sw;
        sw.Start();

        m_allClasses.clear(); // clear the cache
        m_db.Begin();
        for(size_t i = 0; i < files.GetCount(); ++i) {
            if(pFuncGoingDown()) {
                break;
            }
            {
                clParseEvent event(wxPHP_PARSE_PROGRESS);
                event.SetTotalFiles(files.GetCount());
                event.SetCurfileIndex(i);
                event.SetFileName(files.Item(i));
                EventNotifier::Get()->AddPendingEvent(event);
            }

            wxFileName fnFile(files.Item(i));
            bool reParseNeeded(true);

            if(updateMode == kUpdateMode_Fast) {
                // Check to see if we need to re-parse this file
                // and store it to the database

                if(!fnFile.Exists()) {
                    reParseNeeded = false;
                } else {
                    time_t lastModifiedOnDisk = fnFile.GetModificationTime().GetTicks();
                    wxLongLong lastModifiedInDB = GetFileLastParsedTimestamp(fnFile);
                    if(lastModifiedOnDisk <= lastModifiedInDB.ToLong()) {
                        reParseNeeded = false;
                    }
                }
            }

            // Ensure that the file exists
            if(!fnFile.Exists()) {
                reParseNeeded = false;
            }

            // Parse only valid PHP files
            if(FileExtManager::GetType(fnFile.GetFullName()) != FileExtManager::TypePhp) {
                reParseNeeded = false;
            }

            if(reParseNeeded) {
                // For performance reaons, load the file into memory and then parse it
                wxFileName fnSourceFile(files.Item(i));
                wxString content;
                if(!FileUtils::ReadFileContent(fnSourceFile, content, wxConvISO8859_1)) {
                    clWARNING() << "PHP: Failed to read file:" << fnSourceFile << "for parsing" << clEndl;
                    continue;
                }
                PHPSourceFile sourceFile(content, this);
                sourceFile.SetFilename(fnSourceFile);
                sourceFile.SetParseFunctionBody(parseFuncBodies);
                sourceFile.Parse();
                UpdateSourceFile(sourceFile, false);
            }
        }
        m_db.Commit();
        long elapsedMs = sw.Time();

        LOG_IF_TRACE
        {
            clDEBUG1() << _("PHP: parsed ") << files.GetCount() << " in " << elapsedMs << " milliseconds" << clEndl;
        }

        {
            clParseEvent event(wxPHP_PARSE_ENDED);
            event.SetTotalFiles(files.GetCount());
            event.SetCurfileIndex(files.GetCount());
            EventNotifier::Get()->AddPendingEvent(event);
        }

    } catch(wxSQLite3Exception& e) {
        try {
            m_db.Rollback();

        } catch(...) {
        }

        {
            // always make sure that the end event is sent
            clParseEvent event(wxPHP_PARSE_ENDED);
            event.SetTotalFiles(files.GetCount());
            event.SetCurfileIndex(files.GetCount());
            EventNotifier::Get()->AddPendingEvent(event);
        }

        clWARNING() << "PHPLookupTable::UpdateSourceFiles:" << e.GetMessage() << clEndl;
    }
}

#endif // PHPLOOKUPTABLE_H