This commit is contained in:
Fangrui Song 2018-04-07 17:10:54 -07:00
parent 3fbfb99e1b
commit b872faa160
65 changed files with 398 additions and 526 deletions

View File

@ -211,6 +211,7 @@ target_sources(ccls PRIVATE
src/diagnostics_engine.cc src/diagnostics_engine.cc
src/file_consumer.cc src/file_consumer.cc
src/file_contents.cc src/file_contents.cc
src/filesystem.cc
src/fuzzy_match.cc src/fuzzy_match.cc
src/iindexer.cc src/iindexer.cc
src/import_manager.cc src/import_manager.cc

View File

@ -67,7 +67,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 10983126130596230582, "usr": 18410644574635149442,
"detailed_name": "Foo f", "detailed_name": "Foo f",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "f", "short_name": "f",
@ -80,7 +80,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 17165811951126099095, "usr": 11468802633764653592,
"detailed_name": "Foo *f2", "detailed_name": "Foo *f2",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "f2", "short_name": "f2",

View File

@ -89,7 +89,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 1893354193220338759, "usr": 9954632887635271906,
"detailed_name": "Foo f", "detailed_name": "Foo f",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "f", "short_name": "f",

View File

@ -66,7 +66,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 449111627548814328, "usr": 17348451315735351657,
"detailed_name": "Type foo0", "detailed_name": "Type foo0",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "foo0", "short_name": "foo0",
@ -79,7 +79,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 17097499197730163115, "usr": 3757978174345638825,
"detailed_name": "Type foo1", "detailed_name": "Type foo1",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "foo1", "short_name": "foo1",

View File

@ -143,7 +143,7 @@ OUTPUT: make_functions.cc
"skipped_by_preprocessor": [], "skipped_by_preprocessor": [],
"types": [{ "types": [{
"id": 0, "id": 0,
"usr": 9281343527065946499, "usr": 7902098450755788854,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -160,7 +160,7 @@ OUTPUT: make_functions.cc
"uses": ["4:1-4:2|-1|1|4"] "uses": ["4:1-4:2|-1|1|4"]
}, { }, {
"id": 1, "id": 1,
"usr": 10771590811355716928, "usr": 12533159752419999454,
"detailed_name": "Args", "detailed_name": "Args",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "Args", "short_name": "Args",
@ -177,7 +177,7 @@ OUTPUT: make_functions.cc
"uses": ["4:15-4:19|-1|1|4"] "uses": ["4:15-4:19|-1|1|4"]
}, { }, {
"id": 2, "id": 2,
"usr": 11897454629873246477, "usr": 18441628706991062891,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -194,7 +194,7 @@ OUTPUT: make_functions.cc
"uses": ["9:1-9:2|-1|1|4"] "uses": ["9:1-9:2|-1|1|4"]
}, { }, {
"id": 3, "id": 3,
"usr": 3337128087216004141, "usr": 9441341235704820385,
"detailed_name": "Args", "detailed_name": "Args",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "Args", "short_name": "Args",
@ -347,7 +347,7 @@ OUTPUT: make_functions.cc
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 8463700030555379526, "usr": 15288691366352169805,
"detailed_name": "Args &&... args", "detailed_name": "Args &&... args",
"qual_name_offset": 11, "qual_name_offset": 11,
"short_name": "args", "short_name": "args",
@ -359,7 +359,7 @@ OUTPUT: make_functions.cc
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 3908732770590594660, "usr": 12338908251430965107,
"detailed_name": "Args... args", "detailed_name": "Args... args",
"qual_name_offset": 8, "qual_name_offset": 8,
"short_name": "args", "short_name": "args",

View File

@ -53,7 +53,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 14555488990109936920, "usr": 10480417713467708012,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",
@ -66,7 +66,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 10963664335057337329, "usr": 18099600680625658464,
"detailed_name": "int b", "detailed_name": "int b",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "b", "short_name": "b",

View File

@ -102,7 +102,7 @@ OUTPUT:
"uses": ["13:56-13:64|-1|1|4"] "uses": ["13:56-13:64|-1|1|4"]
}, { }, {
"id": 5, "id": 5,
"usr": 7916588271848318236, "usr": 780719166805015998,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -138,7 +138,7 @@ OUTPUT:
"funcs": [], "funcs": [],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 12990052348105569112, "usr": 3880651725784125791,
"detailed_name": "unsigned int T", "detailed_name": "unsigned int T",
"qual_name_offset": 13, "qual_name_offset": 13,
"short_name": "T", "short_name": "T",

View File

@ -33,7 +33,7 @@ OUTPUT:
"uses": [] "uses": []
}, { }, {
"id": 1, "id": 1,
"usr": 14635009347499519042, "usr": 1287417953265234030,
"detailed_name": "", "detailed_name": "",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "", "short_name": "",
@ -65,7 +65,7 @@ OUTPUT:
"callees": ["9:14-9:15|1|3|32", "10:14-10:15|1|3|32", "11:14-11:15|1|3|32"] "callees": ["9:14-9:15|1|3|32", "10:14-10:15|1|3|32", "11:14-11:15|1|3|32"]
}, { }, {
"id": 1, "id": 1,
"usr": 17926497908620168464, "usr": 1328781044864682611,
"detailed_name": "", "detailed_name": "",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "", "short_name": "",
@ -80,7 +80,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 12666114896600231317, "usr": 17270098654620601683,
"detailed_name": "int x", "detailed_name": "int x",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "x", "short_name": "x",
@ -93,7 +93,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 2981279427664991319, "usr": 16806544259835773270,
"detailed_name": "lambda dosomething", "detailed_name": "lambda dosomething",
"qual_name_offset": 7, "qual_name_offset": 7,
"short_name": "dosomething", "short_name": "dosomething",
@ -106,7 +106,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 2, "id": 2,
"usr": 12879188959314906706, "usr": 2034725908368218782,
"detailed_name": "int y", "detailed_name": "int y",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "y", "short_name": "y",

View File

@ -92,7 +92,7 @@ OUTPUT:
"storage": 0 "storage": 0
}, { }, {
"id": 2, "id": 2,
"usr": 2056319845419860263, "usr": 14946041066794678724,
"detailed_name": "DISALLOW", "detailed_name": "DISALLOW",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "DISALLOW", "short_name": "DISALLOW",

View File

@ -26,7 +26,7 @@ OUTPUT:
"funcs": [{ "funcs": [{
"id": 0, "id": 0,
"usr": 5010253035933134245, "usr": 5010253035933134245,
"detailed_name": "void (anon)::foo()", "detailed_name": "void (anon ns)::foo()",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "foo", "short_name": "foo",
"kind": 12, "kind": 12,

View File

@ -150,7 +150,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 6030927277961448585, "usr": 107714981785063096,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",
@ -164,7 +164,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 2, "id": 2,
"usr": 7657277353101371136, "usr": 1200087780658383286,
"detailed_name": "int b", "detailed_name": "int b",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "b", "short_name": "b",

View File

@ -111,7 +111,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 3649375698083002347, "usr": 7976909968919750794,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",

View File

@ -187,7 +187,7 @@ OUTPUT: static_function_in_type.cc
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 13569879755236306838, "usr": 9285345059965948351,
"detailed_name": "ns::Manager *m", "detailed_name": "ns::Manager *m",
"qual_name_offset": 13, "qual_name_offset": 13,
"short_name": "m", "short_name": "m",

View File

@ -12,7 +12,7 @@ OUTPUT:
"funcs": [], "funcs": [],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 11674328179498211370, "usr": 13076155634261037336,
"detailed_name": "FOO", "detailed_name": "FOO",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "FOO", "short_name": "FOO",

View File

@ -87,7 +87,7 @@ OUTPUT:
"uses": ["10:26-10:32|-1|1|4", "13:13-13:19|-1|1|4", "14:14-14:20|-1|1|4"] "uses": ["10:26-10:32|-1|1|4", "13:13-13:19|-1|1|4", "14:14-14:20|-1|1|4"]
}, { }, {
"id": 4, "id": 4,
"usr": 2205716167465743256, "usr": 14511917000226829276,
"detailed_name": "", "detailed_name": "",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "", "short_name": "",

View File

@ -83,7 +83,7 @@ OUTPUT:
"uses": ["7:1-7:9|-1|1|4"] "uses": ["7:1-7:9|-1|1|4"]
}, { }, {
"id": 2, "id": 2,
"usr": 9673599782548740467, "usr": 10862637711685426953,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -100,7 +100,7 @@ OUTPUT:
"uses": ["5:16-5:17|-1|1|4"] "uses": ["5:16-5:17|-1|1|4"]
}, { }, {
"id": 3, "id": 3,
"usr": 7143192229126273961, "usr": 756188769017350739,
"detailed_name": "Args", "detailed_name": "Args",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "Args", "short_name": "Args",
@ -166,7 +166,7 @@ OUTPUT:
"uses": ["31:1-31:7|-1|1|4"] "uses": ["31:1-31:7|-1|1|4"]
}, { }, {
"id": 7, "id": 7,
"usr": 8880262253425334092, "usr": 3421332160420436276,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -251,7 +251,7 @@ OUTPUT:
"uses": [] "uses": []
}, { }, {
"id": 12, "id": 12,
"usr": 14111105212951082474, "usr": 2461355892344618654,
"detailed_name": "T", "detailed_name": "T",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "T", "short_name": "T",
@ -433,7 +433,7 @@ OUTPUT:
"storage": 0 "storage": 0
}, { }, {
"id": 7, "id": 7,
"usr": 17826688417349629938, "usr": 10307767688451422448,
"detailed_name": "T Value", "detailed_name": "T Value",
"qual_name_offset": 2, "qual_name_offset": 2,
"short_name": "Value", "short_name": "Value",

View File

@ -71,7 +71,7 @@ OUTPUT:
"uses": ["8:1-8:2|-1|1|4", "8:11-8:12|-1|1|4"] "uses": ["8:1-8:2|-1|1|4", "8:11-8:12|-1|1|4"]
}, { }, {
"id": 2, "id": 2,
"usr": 11919899838872947844, "usr": 8864163146308556810,
"detailed_name": "", "detailed_name": "",
"qual_name_offset": 0, "qual_name_offset": 0,
"short_name": "", "short_name": "",

View File

@ -64,7 +64,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 16088407831770615719, "usr": 13681544683892648258,
"detailed_name": "void (*)() x", "detailed_name": "void (*)() x",
"qual_name_offset": 11, "qual_name_offset": 11,
"short_name": "x", "short_name": "x",

View File

@ -67,7 +67,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 4636142131003982569, "usr": 8436636043513449412,
"detailed_name": "void (Foo::*)() x", "detailed_name": "void (Foo::*)() x",
"qual_name_offset": 16, "qual_name_offset": 16,
"short_name": "x", "short_name": "x",

View File

@ -67,7 +67,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 14045150712868309451, "usr": 3014406561587537195,
"detailed_name": "Foo *f", "detailed_name": "Foo *f",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "f", "short_name": "f",

View File

@ -66,7 +66,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 16229832321010999607, "usr": 12410753116854389823,
"detailed_name": "Foo *f", "detailed_name": "Foo *f",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "f", "short_name": "f",

View File

@ -95,7 +95,7 @@ OUTPUT:
"storage": 3 "storage": 3
}, { }, {
"id": 2, "id": 2,
"usr": 3364438781074774169, "usr": 2462000803278878465,
"detailed_name": "unique_ptr<S> *local", "detailed_name": "unique_ptr<S> *local",
"qual_name_offset": 15, "qual_name_offset": 15,
"short_name": "local", "short_name": "local",

View File

@ -228,7 +228,7 @@ OUTPUT:
"storage": 2 "storage": 2
}, { }, {
"id": 1, "id": 1,
"usr": 500112618220246, "usr": 11547294959889394856,
"detailed_name": "unique_ptr<unique_ptr<S1, S2>, S2> *local", "detailed_name": "unique_ptr<unique_ptr<S1, S2>, S2> *local",
"qual_name_offset": 36, "qual_name_offset": 36,
"short_name": "local", "short_name": "local",

View File

@ -63,7 +63,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 16374832544037266261, "usr": 11033478034711123650,
"detailed_name": "ForwardType *a", "detailed_name": "ForwardType *a",
"qual_name_offset": 13, "qual_name_offset": 13,
"short_name": "a", "short_name": "a",
@ -76,7 +76,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 2580122838476012357, "usr": 8949902309768550158,
"detailed_name": "ImplementedType b", "detailed_name": "ImplementedType b",
"qual_name_offset": 16, "qual_name_offset": 16,
"short_name": "b", "short_name": "b",

View File

@ -60,7 +60,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 13058491096576226774, "usr": 2584795197111552890,
"detailed_name": "ForwardType *f", "detailed_name": "ForwardType *f",
"qual_name_offset": 13, "qual_name_offset": 13,
"short_name": "f", "short_name": "f",
@ -73,7 +73,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 11055777568039014776, "usr": 5136230284979460117,
"detailed_name": "ImplementedType a", "detailed_name": "ImplementedType a",
"qual_name_offset": 16, "qual_name_offset": 16,
"short_name": "a", "short_name": "a",

View File

@ -51,7 +51,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 13823260660189154978, "usr": 2161866804398917919,
"detailed_name": "Foo *f", "detailed_name": "Foo *f",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "f", "short_name": "f",

View File

@ -48,7 +48,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 7997456978847868736, "usr": 16414210592877294238,
"detailed_name": "Type &a0", "detailed_name": "Type &a0",
"qual_name_offset": 6, "qual_name_offset": 6,
"short_name": "a0", "short_name": "a0",
@ -61,7 +61,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 17228576662112939520, "usr": 11558141642862804306,
"detailed_name": "const Type &a1", "detailed_name": "const Type &a1",
"qual_name_offset": 12, "qual_name_offset": 12,
"short_name": "a1", "short_name": "a1",
@ -74,7 +74,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 2, "id": 2,
"usr": 15429032129697337561, "usr": 1536316608590232194,
"detailed_name": "Type a2", "detailed_name": "Type a2",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "a2", "short_name": "a2",
@ -87,7 +87,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 3, "id": 3,
"usr": 6081981442495435784, "usr": 316760354845869406,
"detailed_name": "Type *a3", "detailed_name": "Type *a3",
"qual_name_offset": 6, "qual_name_offset": 6,
"short_name": "a3", "short_name": "a3",
@ -100,7 +100,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 4, "id": 4,
"usr": 5004072032239834773, "usr": 12321730890779907974,
"detailed_name": "const Type *a4", "detailed_name": "const Type *a4",
"qual_name_offset": 12, "qual_name_offset": 12,
"short_name": "a4", "short_name": "a4",
@ -113,7 +113,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 5, "id": 5,
"usr": 14939253431683105646, "usr": 4771437488905761633,
"detailed_name": "const Type *const a5", "detailed_name": "const Type *const a5",
"qual_name_offset": 18, "qual_name_offset": 18,
"short_name": "a5", "short_name": "a5",

View File

@ -55,7 +55,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 16380484338511689669, "usr": 14873619387499024780,
"detailed_name": "Foo f", "detailed_name": "Foo f",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "f", "short_name": "f",

View File

@ -132,7 +132,7 @@ OUTPUT:
"storage": 0 "storage": 0
}, { }, {
"id": 2, "id": 2,
"usr": 8039186520399841081, "usr": 13284113377394221067,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",

View File

@ -48,7 +48,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 9121974011454213596, "usr": 3510529098767253033,
"detailed_name": "void (*)() x", "detailed_name": "void (*)() x",
"qual_name_offset": 11, "qual_name_offset": 11,
"short_name": "x", "short_name": "x",

View File

@ -134,7 +134,7 @@ OUTPUT:
"storage": 0 "storage": 0
}, { }, {
"id": 2, "id": 2,
"usr": 14669930844300034456, "usr": 16303259148898744165,
"detailed_name": "Foo f", "detailed_name": "Foo f",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "f", "short_name": "f",

View File

@ -42,7 +42,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 14014650769929566957, "usr": 8534460107894911680,
"detailed_name": "int x", "detailed_name": "int x",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "x", "short_name": "x",

View File

@ -47,7 +47,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 13311055950748663970, "usr": 17941402366659878910,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",
@ -60,7 +60,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 14036425367303419504, "usr": 11094102496276744608,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",

View File

@ -60,7 +60,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 6997229590862003559, "usr": 8011559936501990179,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",

View File

@ -46,7 +46,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 10601729374837386290, "usr": 9275666070987716270,
"detailed_name": "Foo *x", "detailed_name": "Foo *x",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "x", "short_name": "x",
@ -59,7 +59,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 18422884837902130475, "usr": 16202433437488621027,
"detailed_name": "Foo *y", "detailed_name": "Foo *y",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "y", "short_name": "y",

View File

@ -44,7 +44,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 13198746475679542317, "usr": 10782632605670042066,
"detailed_name": "Foo *a", "detailed_name": "Foo *a",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "a", "short_name": "a",

View File

@ -42,7 +42,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 8730439006497971620, "usr": 4580260577538694711,
"detailed_name": "Foo *p0", "detailed_name": "Foo *p0",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "p0", "short_name": "p0",
@ -55,7 +55,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 2525014371090380500, "usr": 12071725611268840435,
"detailed_name": "Foo *p1", "detailed_name": "Foo *p1",
"qual_name_offset": 5, "qual_name_offset": 5,
"short_name": "p1", "short_name": "p1",

View File

@ -47,7 +47,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 1894874819807168345, "usr": 3440226937504376525,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",
@ -60,7 +60,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 4508045017817092115, "usr": 14700715011944976607,
"detailed_name": "int a", "detailed_name": "int a",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "a", "short_name": "a",

View File

@ -54,7 +54,7 @@ OUTPUT:
"storage": 1 "storage": 1
}, { }, {
"id": 1, "id": 1,
"usr": 11404600766177939811, "usr": 2147918703972955240,
"detailed_name": "int p", "detailed_name": "int p",
"qual_name_offset": 4, "qual_name_offset": 4,
"short_name": "p", "short_name": "p",

View File

@ -67,7 +67,7 @@ OUTPUT:
}], }],
"vars": [{ "vars": [{
"id": 0, "id": 0,
"usr": 6975456769752895964, "usr": 7730100248624586522,
"detailed_name": "F a", "detailed_name": "F a",
"qual_name_offset": 2, "qual_name_offset": 2,
"short_name": "a", "short_name": "a",

View File

@ -1,6 +1,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "clang_utils.h" #include "clang_utils.h"
#include "filesystem.hh"
#include "platform.h" #include "platform.h"
#include "timer.h" #include "timer.h"
@ -27,6 +28,11 @@ unsigned Flags() {
; ;
} }
std::string StripFileType(const std::string& path) {
fs::path p(path);
return p.parent_path() / p.stem();
}
unsigned GetCompletionPriority(const CXCompletionString& str, unsigned GetCompletionPriority(const CXCompletionString& str,
CXCursorKind result_kind, CXCursorKind result_kind,
const std::optional<std::string>& typedText) { const std::optional<std::string>& typedText) {
@ -671,12 +677,12 @@ ClangCompleteManager::ClangCompleteManager(Project* project,
preloaded_sessions_(kMaxPreloadedSessions), preloaded_sessions_(kMaxPreloadedSessions),
completion_sessions_(kMaxCompletionSessions) { completion_sessions_(kMaxCompletionSessions) {
new std::thread([&]() { new std::thread([&]() {
SetCurrentThreadName("completequery"); SetThreadName("completequery");
CompletionQueryMain(this); CompletionQueryMain(this);
}); });
new std::thread([&]() { new std::thread([&]() {
SetCurrentThreadName("completeparse"); SetThreadName("completeparse");
CompletionParseMain(this); CompletionParseMain(this);
}); });
} }

View File

@ -2304,7 +2304,7 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
if (ls_diagnostic.severity != lsDiagnosticSeverity::Error) if (ls_diagnostic.severity != lsDiagnosticSeverity::Error)
continue; continue;
ls_diagnostic.range = ls_diagnostic.range =
lsRange(lsPosition(line, 10), lsPosition(line, 10)); lsRange{lsPosition{line, 10}, lsPosition{line, 10}};
param.primary_file->diagnostics_.push_back(ls_diagnostic); param.primary_file->diagnostics_.push_back(ls_diagnostic);
break; break;
} }

View File

@ -15,8 +15,8 @@ lsRange GetLsRangeForFixIt(const CXSourceRange& range) {
unsigned int end_line, end_column; unsigned int end_line, end_column;
clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr); clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr);
return lsRange(lsPosition(start_line - 1, start_column - 1) /*start*/, return lsRange{lsPosition{int(start_line) - 1, int(start_column) - 1},
lsPosition(end_line - 1, end_column) /*end*/); lsPosition{int(end_line) - 1, int(end_column)}};
} }
} // namespace } // namespace
@ -59,8 +59,8 @@ std::optional<lsDiagnostic> BuildAndDisposeDiagnostic(CXDiagnostic diagnostic,
// Build diagnostic. // Build diagnostic.
lsDiagnostic ls_diagnostic; lsDiagnostic ls_diagnostic;
ls_diagnostic.range = lsRange(lsPosition(start_line - 1, start_column - 1), ls_diagnostic.range = lsRange{{int(start_line) - 1, int(start_column) - 1},
lsPosition(end_line - 1, end_column - 1)); {int(end_line) - 1, int(end_column) - 1}};
ls_diagnostic.message = ToString(clang_getDiagnosticSpelling(diagnostic)); ls_diagnostic.message = ToString(clang_getDiagnosticSpelling(diagnostic));

View File

@ -31,9 +31,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <functional> #include <functional>
#include <iostream>
#include <iterator> #include <iterator>
#include <string> #include <string>
#include <thread>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -76,8 +76,7 @@ bool ShouldDisplayMethodTiming(MethodType type) {
} }
void PrintHelp() { void PrintHelp() {
std::cout printf("%s", R"help(ccls is a C/C++/Objective-C language server.
<< R"help(ccls is a C/C++/Objective-C language server.
Mode: Mode:
--test-unit Run unit tests. --test-unit Run unit tests.
@ -101,7 +100,7 @@ Other command line options:
out. out.
See more on https://github.com/MaskRay/ccls/wiki See more on https://github.com/MaskRay/ccls/wiki
)help"; )help");
} }
} // namespace } // namespace
@ -214,7 +213,7 @@ void RunQueryDbThread(const std::string& bin_name,
} }
// Run query db main loop. // Run query db main loop.
SetCurrentThreadName("querydb"); SetThreadName("querydb");
while (true) { while (true) {
bool did_work = QueryDbMainLoop( bool did_work = QueryDbMainLoop(
&db, querydb_waiter, &project, &file_consumer_shared, &db, querydb_waiter, &project, &file_consumer_shared,
@ -244,11 +243,8 @@ void RunQueryDbThread(const std::string& bin_name,
// //
// |ipc| is connected to a server. // |ipc| is connected to a server.
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) { void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
// If flushing cin requires flushing cout there could be deadlocks in some new std::thread([request_times]() {
// clients. SetThreadName("stdin");
std::cin.tie(nullptr);
StartThread("stdin", [request_times]() {
auto* queue = QueueManager::instance(); auto* queue = QueueManager::instance();
while (true) { while (true) {
std::unique_ptr<InMessage> message; std::unique_ptr<InMessage> message;
@ -288,7 +284,8 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times, void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
MultiQueueWaiter* waiter) { MultiQueueWaiter* waiter) {
StartThread("stdout", [=]() { new std::thread([=]() {
SetThreadName("stdout");
auto* queue = QueueManager::instance(); auto* queue = QueueManager::instance();
while (true) { while (true) {
@ -387,9 +384,8 @@ int main(int argc, char** argv) {
rapidjson::Document reader; rapidjson::Document reader;
rapidjson::ParseResult ok = reader.Parse(g_init_options.c_str()); rapidjson::ParseResult ok = reader.Parse(g_init_options.c_str());
if (!ok) { if (!ok) {
std::cerr << "Failed to parse --init as JSON: " fprintf(stderr, "Failed to parse --init as JSON: %s (%zd)\n",
<< rapidjson::GetParseError_En(ok.Code()) << " (" rapidjson::GetParseError_En(ok.Code()), ok.Offset());
<< ok.Offset() << ")\n";
return 1; return 1;
} }
JsonReader json_reader{&reader}; JsonReader json_reader{&reader};
@ -397,9 +393,9 @@ int main(int argc, char** argv) {
Config config; Config config;
Reflect(json_reader, config); Reflect(json_reader, config);
} catch (std::invalid_argument& e) { } catch (std::invalid_argument& e) {
std::cerr << "Fail to parse --init " fprintf(stderr, "Failed to parse --init %s, expected %s\n",
<< static_cast<JsonReader&>(json_reader).GetPath() static_cast<JsonReader&>(json_reader).GetPath().c_str(),
<< ", expected " << e.what() << "\n"; e.what());
return 1; return 1;
} }
} }

43
src/filesystem.cc Normal file
View File

@ -0,0 +1,43 @@
#include "filesystem.hh"
#include "utils.h"
#include <queue>
#include <utility>
static void GetFilesInFolderHelper(
std::string folder,
bool recursive,
std::string output_prefix,
const std::function<void(const std::string&)>& handler) {
std::queue<std::pair<fs::path, fs::path>> q;
q.emplace(fs::path(folder), fs::path(output_prefix));
while (!q.empty()) {
for (auto it = fs::directory_iterator(q.front().first); it != fs::directory_iterator(); ++it) {
auto path = it->path();
std::string filename = path.filename();
if (filename[0] != '.' || filename == ".ccls") {
fs::file_status status = it->symlink_status();
if (fs::is_regular_file(status))
handler(q.front().second / filename);
else if (fs::is_directory(status) || fs::is_symlink(status)) {
if (recursive) {
std::string child_dir = q.front().second / filename;
if (fs::is_directory(status))
q.push(make_pair(path, child_dir));
}
}
}
}
q.pop();
}
}
void GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path,
const std::function<void(const std::string&)>& handler) {
EnsureEndsInSlash(folder);
GetFilesInFolderHelper(folder, recursive, add_folder_to_path ? folder : "",
handler);
}

View File

@ -1,5 +1,12 @@
#pragma once #pragma once
#include <experimental/filesystem> #include <experimental/filesystem>
#include <functional>
#include <string>
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
void GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path,
const std::function<void(const std::string&)>& handler);

View File

@ -1,11 +1,14 @@
#include "include_complete.h" #include "include_complete.h"
#include "filesystem.hh"
#include "match.h" #include "match.h"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "standard_includes.h" #include "standard_includes.h"
#include "timer.h" #include "timer.h"
#include <thread>
namespace { namespace {
struct CompletionCandidate { struct CompletionCandidate {
@ -112,7 +115,8 @@ void IncludeComplete::Rescan() {
g_config->completion.includeBlacklist); g_config->completion.includeBlacklist);
is_scanning = true; is_scanning = true;
StartThread("scan_includes", [this]() { new std::thread([this]() {
SetThreadName("scan_includes");
Timer timer; Timer timer;
InsertStlIncludes(); InsertStlIncludes();

View File

@ -69,21 +69,21 @@ std::pair<bool, int> CaseFoldingSubsequenceMatch(std::string_view search,
TEST_SUITE("Offset") { TEST_SUITE("Offset") {
TEST_CASE("past end") { TEST_CASE("past end") {
std::string content = "foo"; std::string content = "foo";
int offset = GetOffsetForPosition(lsPosition(10, 10), content); int offset = GetOffsetForPosition(lsPosition{10, 10}, content);
REQUIRE(offset <= content.size()); REQUIRE(offset <= content.size());
} }
TEST_CASE("in middle of content") { TEST_CASE("in middle of content") {
std::string content = "abcdefghijk"; std::string content = "abcdefghijk";
for (int i = 0; i < content.size(); ++i) { for (int i = 0; i < content.size(); ++i) {
int offset = GetOffsetForPosition(lsPosition(0, i), content); int offset = GetOffsetForPosition(lsPosition{0, i}, content);
REQUIRE(i == offset); REQUIRE(i == offset);
} }
} }
TEST_CASE("at end of content") { TEST_CASE("at end of content") {
REQUIRE(GetOffsetForPosition(lsPosition(0, 0), "") == 0); REQUIRE(GetOffsetForPosition(lsPosition{0, 0}, "") == 0);
REQUIRE(GetOffsetForPosition(lsPosition(0, 1), "a") == 1); REQUIRE(GetOffsetForPosition(lsPosition{0, 1}, "a") == 1);
} }
} }

View File

@ -269,46 +269,9 @@ std::string lsDocumentUri::GetPath() const {
return ret; return ret;
} }
lsPosition::lsPosition() {}
lsPosition::lsPosition(int line, int character)
: line(line), character(character) {}
bool lsPosition::operator==(const lsPosition& other) const {
return line == other.line && character == other.character;
}
bool lsPosition::operator<(const lsPosition& other) const {
return line != other.line ? line < other.line : character < other.character;
}
std::string lsPosition::ToString() const { std::string lsPosition::ToString() const {
return std::to_string(line) + ":" + std::to_string(character); return std::to_string(line) + ":" + std::to_string(character);
} }
const lsPosition lsPosition::kZeroPosition = lsPosition();
lsRange::lsRange() {}
lsRange::lsRange(lsPosition start, lsPosition end) : start(start), end(end) {}
bool lsRange::operator==(const lsRange& o) const {
return start == o.start && end == o.end;
}
bool lsRange::operator<(const lsRange& o) const {
return !(start == o.start) ? start < o.start : end < o.end;
}
lsLocation::lsLocation() {}
lsLocation::lsLocation(lsDocumentUri uri, lsRange range)
: uri(uri), range(range) {}
bool lsLocation::operator==(const lsLocation& o) const {
return uri == o.uri && range == o.range;
}
bool lsLocation::operator<(const lsLocation& o) const {
return std::make_tuple(uri.raw_uri, range) <
std::make_tuple(o.uri.raw_uri, o.range);
}
bool lsTextEdit::operator==(const lsTextEdit& that) { bool lsTextEdit::operator==(const lsTextEdit& that) {
return range == that.range && newText == that.newText; return range == that.range && newText == that.newText;

View File

@ -121,44 +121,42 @@ void Reflect(TVisitor& visitor, lsDocumentUri& value) {
} }
struct lsPosition { struct lsPosition {
lsPosition();
lsPosition(int line, int character);
bool operator==(const lsPosition& other) const;
bool operator<(const lsPosition& other) const;
std::string ToString() const;
// Note: these are 0-based.
int line = 0; int line = 0;
int character = 0; int character = 0;
static const lsPosition kZeroPosition; bool operator==(const lsPosition& o) const {
return line == o.line && character == o.character;
}
bool operator<(const lsPosition& o) const {
return line != o.line ? line < o.line : character < o.character;
}
std::string ToString() const;
}; };
MAKE_HASHABLE(lsPosition, t.line, t.character); MAKE_HASHABLE(lsPosition, t.line, t.character);
MAKE_REFLECT_STRUCT(lsPosition, line, character); MAKE_REFLECT_STRUCT(lsPosition, line, character);
struct lsRange { struct lsRange {
lsRange();
lsRange(lsPosition start, lsPosition end);
bool operator==(const lsRange& other) const;
bool operator<(const lsRange& other) const;
lsPosition start; lsPosition start;
lsPosition end; lsPosition end;
bool operator==(const lsRange& o) const {
return start == o.start && end == o.end;
}
bool operator<(const lsRange& o) const {
return !(start == o.start) ? start < o.start : end < o.end;
}
}; };
MAKE_HASHABLE(lsRange, t.start, t.end); MAKE_HASHABLE(lsRange, t.start, t.end);
MAKE_REFLECT_STRUCT(lsRange, start, end); MAKE_REFLECT_STRUCT(lsRange, start, end);
struct lsLocation { struct lsLocation {
lsLocation();
lsLocation(lsDocumentUri uri, lsRange range);
bool operator==(const lsLocation& other) const;
bool operator<(const lsLocation& o) const;
lsDocumentUri uri; lsDocumentUri uri;
lsRange range; lsRange range;
bool operator==(const lsLocation& o) const {
return uri == o.uri && range == o.range;
}
bool operator<(const lsLocation& o) const {
return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri
: range < o.range;
}
}; };
MAKE_HASHABLE(lsLocation, t.uri, t.range); MAKE_HASHABLE(lsLocation, t.uri, t.range);
MAKE_REFLECT_STRUCT(lsLocation, uri, range); MAKE_REFLECT_STRUCT(lsLocation, uri, range);

View File

@ -332,8 +332,8 @@ void EmitSemanticHighlighting(QueryDatabase* db,
// Attribute range [events[i-1].pos, events[i].pos) to events[top-1].symbol // Attribute range [events[i-1].pos, events[i].pos) to events[top-1].symbol
// . // .
if (top && !(events[i - 1].pos == events[i].pos)) if (top && !(events[i - 1].pos == events[i].pos))
events[top - 1].symbol->ranges.emplace_back(events[i - 1].pos, events[top - 1].symbol->ranges.push_back(
events[i].pos); lsRange{events[i - 1].pos, events[i].pos});
if (events[i].id >= 0) if (events[i].id >= 0)
events[top++] = events[i]; events[top++] = events[i];
else else

View File

@ -517,11 +517,12 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
std::max(int(std::thread::hardware_concurrency() * 0.8), 1); std::max(int(std::thread::hardware_concurrency() * 0.8), 1);
} }
LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers"; LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers";
for (int i = 0; i < g_config->index.threads; ++i) { for (int i = 0; i < g_config->index.threads; i++) {
StartThread("indexer" + std::to_string(i), [=]() { new std::thread([=]() {
Indexer_Main(diag_engine, file_consumer_shared, SetThreadName("indexer" + std::to_string(i));
timestamp_manager, import_manager, Indexer_Main(diag_engine, file_consumer_shared, timestamp_manager,
import_pipeline_status, project, working_files, waiter); import_manager, import_pipeline_status, project,
working_files, waiter);
}); });
} }

View File

@ -12,7 +12,7 @@ void PlatformInit();
std::string GetExecutablePath(); std::string GetExecutablePath();
std::string NormalizePath(const std::string& path); std::string NormalizePath(const std::string& path);
void SetCurrentThreadName(const std::string& thread_name); void SetThreadName(const std::string& thread_name);
std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path); std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path);

View File

@ -155,7 +155,7 @@ std::string NormalizePath(const std::string& path) {
return resolved ? *resolved : path; return resolved ? *resolved : path;
} }
void SetCurrentThreadName(const std::string& thread_name) { void SetThreadName(const std::string& thread_name) {
loguru::set_thread_name(thread_name.c_str()); loguru::set_thread_name(thread_name.c_str());
#if defined(__APPLE__) #if defined(__APPLE__)
pthread_setname_np(thread_name.c_str()); pthread_setname_np(thread_name.c_str());

View File

@ -15,7 +15,6 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream>
#include <string> #include <string>
void PlatformInit() { void PlatformInit() {
@ -60,7 +59,7 @@ typedef struct tagTHREADNAME_INFO {
DWORD dwFlags; // Reserved for future use, must be zero. DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO; } THREADNAME_INFO;
#pragma pack(pop) #pragma pack(pop)
void SetCurrentThreadName(const std::string& thread_name) { void SetThreadName(const std::string& thread_name) {
loguru::set_thread_name(thread_name.c_str()); loguru::set_thread_name(thread_name.c_str());
THREADNAME_INFO info; THREADNAME_INFO info;

View File

@ -21,6 +21,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <fstream>
#include <limits> #include <limits>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
@ -47,7 +48,7 @@ struct ProjectConfig {
std::unordered_set<std::string> quote_dirs; std::unordered_set<std::string> quote_dirs;
std::unordered_set<std::string> angle_dirs; std::unordered_set<std::string> angle_dirs;
std::vector<std::string> extra_flags; std::vector<std::string> extra_flags;
std::string project_dir; fs::path project_dir;
ProjectMode mode = ProjectMode::CompileCommandsJson; ProjectMode mode = ProjectMode::CompileCommandsJson;
}; };
@ -107,7 +108,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
const CompileCommandsEntry& entry) { const CompileCommandsEntry& entry) {
Project::Entry result; Project::Entry result;
result.filename = entry.file; result.filename = entry.file;
const std::string base_name = GetBaseName(entry.file); const std::string base_name = fs::path(entry.file).filename();
// Expand %c %cpp %clang // Expand %c %cpp %clang
std::vector<std::string> args; std::vector<std::string> args;
@ -256,7 +257,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
std::vector<std::string> ReadCompilerArgumentsFromFile( std::vector<std::string> ReadCompilerArgumentsFromFile(
const std::string& path) { const std::string& path) {
std::vector<std::string> args; std::vector<std::string> args;
for (std::string line : ReadFileLines(path)) { std::ifstream fin(path);
for (std::string line; std::getline(fin, line);) {
TrimInPlace(line); TrimInPlace(line);
if (line.empty() || StartsWith(line, "#")) if (line.empty() || StartsWith(line, "#"))
continue; continue;
@ -268,7 +270,7 @@ std::vector<std::string> ReadCompilerArgumentsFromFile(
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) { std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
std::vector<Project::Entry> result; std::vector<Project::Entry> result;
config->mode = ProjectMode::DotCcls; config->mode = ProjectMode::DotCcls;
LOG_IF_S(WARNING, !FileExists(config->project_dir + "/.ccls") && LOG_IF_S(WARNING, !fs::exists(config->project_dir / ".ccls") &&
config->extra_flags.empty()) config->extra_flags.empty())
<< "ccls has no clang arguments. Considering adding either a " << "ccls has no clang arguments. Considering adding either a "
"compile_commands.json or .ccls file. See the ccls README for " "compile_commands.json or .ccls file. See the ccls README for "
@ -282,31 +284,31 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
[&folder_args, &files](const std::string& path) { [&folder_args, &files](const std::string& path) {
if (SourceFileLanguage(path) != LanguageId::Unknown) { if (SourceFileLanguage(path) != LanguageId::Unknown) {
files.push_back(path); files.push_back(path);
} else if (GetBaseName(path) == ".ccls") { } else if (fs::path(path).filename() == ".ccls") {
LOG_S(INFO) << "Using .ccls arguments from " << path; LOG_S(INFO) << "Using .ccls arguments from " << path;
folder_args.emplace(GetDirName(path), folder_args.emplace(
fs::path(path).parent_path().string(),
ReadCompilerArgumentsFromFile(path)); ReadCompilerArgumentsFromFile(path));
} }
}); });
const auto& project_dir_args = folder_args[config->project_dir]; const std::string project_dir = config->project_dir.string();
const auto& project_dir_args = folder_args[project_dir];
LOG_IF_S(INFO, !project_dir_args.empty()) LOG_IF_S(INFO, !project_dir_args.empty())
<< "Using .ccls arguments " << StringJoin(project_dir_args); << "Using .ccls arguments " << StringJoin(project_dir_args);
auto GetCompilerArgumentForFile = [&config, auto GetCompilerArgumentForFile = [&project_dir, &folder_args](fs::path cur) {
&folder_args](const std::string& path) { while (!(cur = cur.parent_path()).empty()) {
for (std::string cur = GetDirName(path);; cur = GetDirName(cur)) {
auto it = folder_args.find(cur); auto it = folder_args.find(cur);
if (it != folder_args.end()) if (it != folder_args.end())
return it->second; return it->second;
std::string normalized = NormalizePath(cur); std::string normalized = NormalizePath(cur);
// Break if outside of the project root. // Break if outside of the project root.
if (normalized.size() <= config->project_dir.size() || if (normalized.size() <= project_dir.size() ||
normalized.compare(0, config->project_dir.size(), normalized.compare(0, project_dir.size(), project_dir) != 0)
config->project_dir) != 0)
break; break;
} }
return folder_args[config->project_dir]; return folder_args[project_dir];
}; };
for (const std::string& file : files) { for (const std::string& file : files) {
@ -327,7 +329,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
ProjectConfig* project, ProjectConfig* project,
const std::string& opt_compilation_db_dir) { const std::string& opt_compilation_db_dir) {
// If there is a .ccls file always load using directory listing. // If there is a .ccls file always load using directory listing.
if (FileExists(project->project_dir + ".ccls")) if (fs::exists(project->project_dir / ".ccls"))
return LoadFromDirectoryListing(project); return LoadFromDirectoryListing(project);
// If |compilationDatabaseCommand| is specified, execute it to get the compdb. // If |compilationDatabaseCommand| is specified, execute it to get the compdb.
@ -335,7 +337,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
if (g_config->compilationDatabaseCommand.empty()) { if (g_config->compilationDatabaseCommand.empty()) {
project->mode = ProjectMode::CompileCommandsJson; project->mode = ProjectMode::CompileCommandsJson;
// Try to load compile_commands.json, but fallback to a project listing. // Try to load compile_commands.json, but fallback to a project listing.
comp_db_dir = opt_compilation_db_dir.empty() ? project->project_dir comp_db_dir = opt_compilation_db_dir.empty() ? project->project_dir.string()
: opt_compilation_db_dir; : opt_compilation_db_dir;
} else { } else {
project->mode = ProjectMode::ExternalCommand; project->mode = ProjectMode::ExternalCommand;
@ -522,12 +524,15 @@ Project::Entry Project::FindCompilationEntryForFile(
// |best_entry| probably has its own path in the arguments. We need to remap // |best_entry| probably has its own path in the arguments. We need to remap
// that path to the new filename. // that path to the new filename.
std::string best_entry_base_name = GetBaseName(best_entry->filename); fs::path best_entry_base_name = fs::path(best_entry->filename).filename();
for (std::string& arg : result.args) { for (std::string& arg : result.args) {
try {
if (arg == best_entry->filename || if (arg == best_entry->filename ||
GetBaseName(arg) == best_entry_base_name) { fs::path(arg).filename() == best_entry_base_name) {
arg = filename; arg = filename;
} }
} catch (...) {
}
} }
} }
@ -669,7 +674,7 @@ TEST_SUITE("Project") {
"--foobar", "--foobar",
"-Ia_relative1", "-Ia_relative1",
"--foobar", "--foobar",
"-I", "-isystem",
"a_relative2", "a_relative2",
"--foobar", "--foobar",
"-iquote/q_absolute1", "-iquote/q_absolute1",
@ -691,6 +696,7 @@ TEST_SUITE("Project") {
"/a_absolute1", "/a_absolute2", "/base/a_relative1", "/a_absolute1", "/a_absolute2", "/base/a_relative1",
"/base/a_relative2"}; "/base/a_relative2"};
std::unordered_set<std::string> quote_expected{ std::unordered_set<std::string> quote_expected{
"/a_absolute1", "/a_absolute2", "/base/a_relative1",
"/q_absolute1", "/q_absolute2", "/base/q_relative1", "/q_absolute1", "/q_absolute2", "/base/q_relative1",
"/base/q_relative2"}; "/base/q_relative2"};
REQUIRE(config.angle_dirs == angle_expected); REQUIRE(config.angle_dirs == angle_expected);

View File

@ -158,19 +158,19 @@ std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) {
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file, std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
const Position& position) { const Position& position) {
if (!working_file) if (!working_file)
return lsPosition(position.line, position.column); return lsPosition{position.line, position.column};
int column = position.column; int column = position.column;
if (std::optional<int> start = if (std::optional<int> start =
working_file->GetBufferPosFromIndexPos(position.line, &column, false)) working_file->GetBufferPosFromIndexPos(position.line, &column, false))
return lsPosition(*start, column); return lsPosition{*start, column};
return std::nullopt; return std::nullopt;
} }
std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) { std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
if (!working_file) { if (!working_file) {
return lsRange(lsPosition(location.start.line, location.start.column), return lsRange{lsPosition{location.start.line, location.start.column},
lsPosition(location.end.line, location.end.column)); lsPosition{location.end.line, location.end.column}};
} }
int start_column = location.start.column, end_column = location.end.column; int start_column = location.start.column, end_column = location.end.column;
@ -192,8 +192,8 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& locati
if (*start == *end && start_column > end_column) if (*start == *end && start_column > end_column)
end_column = start_column; end_column = start_column;
return lsRange(lsPosition(*start, start_column), return lsRange{lsPosition{*start, start_column},
lsPosition(*end, end_column)); lsPosition{*end, end_column}};
} }
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
@ -227,7 +227,7 @@ std::optional<lsLocation> GetLsLocation(QueryDatabase* db,
GetLsRange(working_files->GetFileByFilename(path), use.range); GetLsRange(working_files->GetFileByFilename(path), use.range);
if (!range) if (!range)
return std::nullopt; return std::nullopt;
return lsLocation(uri, *range); return lsLocation{uri, *range};
} }
std::optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db, std::optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,

View File

@ -1,11 +1,11 @@
#include "serializer.h" #include "serializer.h"
#include "filesystem.hh"
#include "serializers/json.h" #include "serializers/json.h"
#include "serializers/msgpack.h" #include "serializers/msgpack.h"
#include "indexer.h" #include "indexer.h"
#include <doctest/doctest.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <stdexcept> #include <stdexcept>
@ -153,7 +153,7 @@ void Reflect(Writer& visitor, IndexInclude& value) {
REFLECT_MEMBER_START(); REFLECT_MEMBER_START();
REFLECT_MEMBER(line); REFLECT_MEMBER(line);
if (gTestOutputMode) { if (gTestOutputMode) {
std::string basename = GetBaseName(value.resolved_path); std::string basename = fs::path(value.resolved_path).filename();
if (!StartsWith(value.resolved_path, "&")) if (!StartsWith(value.resolved_path, "&"))
basename = "&" + basename; basename = "&" + basename;
REFLECT_MEMBER2("resolved_path", basename); REFLECT_MEMBER2("resolved_path", basename);
@ -279,7 +279,7 @@ bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
assert(value.Resolve(it->second)->uses.size() == 0); assert(value.Resolve(it->second)->uses.size() == 0);
} }
DefaultReflectMemberStart(visitor); visitor.StartObject();
return true; return true;
} }
template <typename TVisitor> template <typename TVisitor>
@ -441,17 +441,3 @@ std::unique_ptr<IndexFile> Deserialize(
return file; return file;
} }
void SetTestOutputMode() {
gTestOutputMode = true;
}
TEST_SUITE("Serializer utils") {
TEST_CASE("GetBaseName") {
REQUIRE(GetBaseName("foo.cc") == "foo.cc");
REQUIRE(GetBaseName("foo/foo.cc") == "foo.cc");
REQUIRE(GetBaseName("/foo.cc") == "foo.cc");
REQUIRE(GetBaseName("///foo.cc") == "foo.cc");
REQUIRE(GetBaseName("bar/") == ".");
}
}

View File

@ -25,7 +25,6 @@ class Reader {
virtual bool IsBool() = 0; virtual bool IsBool() = 0;
virtual bool IsNull() = 0; virtual bool IsNull() = 0;
virtual bool IsArray() = 0;
virtual bool IsInt() = 0; virtual bool IsInt() = 0;
virtual bool IsInt64() = 0; virtual bool IsInt64() = 0;
virtual bool IsUint64() = 0; virtual bool IsUint64() = 0;
@ -73,7 +72,6 @@ struct IndexFile;
#define REFLECT_MEMBER_START() ReflectMemberStart(visitor, value) #define REFLECT_MEMBER_START() ReflectMemberStart(visitor, value)
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor, value); #define REFLECT_MEMBER_END() ReflectMemberEnd(visitor, value);
#define REFLECT_MEMBER_END1(value) ReflectMemberEnd(visitor, value);
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name) #define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name)
#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value) #define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
@ -315,11 +313,6 @@ void Reflect(Writer& visitor, std::vector<T>& values) {
// ReflectMember // ReflectMember
inline void DefaultReflectMemberStart(Writer& visitor) {
visitor.StartObject();
}
inline void DefaultReflectMemberStart(Reader& visitor) {}
template <typename T> template <typename T>
bool ReflectMemberStart(Reader& visitor, T& value) { bool ReflectMemberStart(Reader& visitor, T& value) {
return false; return false;
@ -356,5 +349,3 @@ std::unique_ptr<IndexFile> Deserialize(
const std::string& serialized_index_content, const std::string& serialized_index_content,
const std::string& file_content, const std::string& file_content,
std::optional<int> expected_version); std::optional<int> expected_version);
void SetTestOutputMode();

View File

@ -15,7 +15,6 @@ class JsonReader : public Reader {
bool IsBool() override { return m_->IsBool(); } bool IsBool() override { return m_->IsBool(); }
bool IsNull() override { return m_->IsNull(); } bool IsNull() override { return m_->IsNull(); }
bool IsArray() override { return m_->IsArray(); }
bool IsInt() override { return m_->IsInt(); } bool IsInt() override { return m_->IsInt(); }
bool IsInt64() override { return m_->IsInt64(); } bool IsInt64() override { return m_->IsInt64(); }
bool IsUint64() override { return m_->IsUint64(); } bool IsUint64() override { return m_->IsUint64(); }

View File

@ -23,7 +23,6 @@ class MessagePackReader : public Reader {
bool IsBool() override { return oh_.get().type == msgpack::type::BOOLEAN; } bool IsBool() override { return oh_.get().type == msgpack::type::BOOLEAN; }
bool IsNull() override { return oh_.get().is_nil(); } bool IsNull() override { return oh_.get().is_nil(); }
bool IsArray() override { return oh_.get().type == msgpack::type::ARRAY; }
bool IsInt() override { bool IsInt() override {
return oh_.get().type == msgpack::type::POSITIVE_INTEGER || return oh_.get().type == msgpack::type::POSITIVE_INTEGER ||
oh_.get().type == msgpack::type::NEGATIVE_INTEGER; oh_.get().type == msgpack::type::NEGATIVE_INTEGER;

View File

@ -1,5 +1,6 @@
#include "test.h" #include "test.h"
#include "filesystem.hh"
#include "indexer.h" #include "indexer.h"
#include "platform.h" #include "platform.h"
#include "serializer.h" #include "serializer.h"
@ -15,7 +16,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fstream> #include <fstream>
#include <iostream>
// The 'diff' utility is available and we can use dprintf(3). // The 'diff' utility is available and we can use dprintf(3).
#if _POSIX_C_SOURCE >= 200809L #if _POSIX_C_SOURCE >= 200809L
@ -23,6 +23,8 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
extern bool gTestOutputMode;
std::string ToString(const rapidjson::Document& document) { std::string ToString(const rapidjson::Document& document) {
rapidjson::StringBuffer buffer; rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
@ -35,6 +37,33 @@ std::string ToString(const rapidjson::Document& document) {
return buffer.GetString(); return buffer.GetString();
} }
struct TextReplacer {
struct Replacement {
std::string from;
std::string to;
};
std::vector<Replacement> replacements;
std::string Apply(const std::string& content) {
std::string result = content;
for (const Replacement& replacement : replacements) {
while (true) {
size_t idx = result.find(replacement.from);
if (idx == std::string::npos)
break;
result.replace(result.begin() + idx,
result.begin() + idx + replacement.from.size(),
replacement.to);
}
}
return result;
}
};
void ParseTestExpectation( void ParseTestExpectation(
const std::string& filename, const std::string& filename,
const std::vector<std::string>& lines_with_endings, const std::vector<std::string>& lines_with_endings,
@ -125,8 +154,7 @@ void DiffDocuments(std::string path,
rapidjson::Document& actual) { rapidjson::Document& actual) {
std::string joined_actual_output = ToString(actual); std::string joined_actual_output = ToString(actual);
std::string joined_expected_output = ToString(expected); std::string joined_expected_output = ToString(expected);
std::cout << "[FAILED] " << path << " (section " << path_section << ")" printf("[FAILED] %s (section %s)\n", path.c_str(), path_section.c_str());
<< std::endl;
#if _POSIX_C_SOURCE >= 200809L #if _POSIX_C_SOURCE >= 200809L
char expected_file[] = "/tmp/ccls.expected.XXXXXX"; char expected_file[] = "/tmp/ccls.expected.XXXXXX";
@ -156,13 +184,10 @@ void DiffDocuments(std::string path,
std::vector<std::string> expected_output = std::vector<std::string> expected_output =
SplitString(joined_expected_output, "\n"); SplitString(joined_expected_output, "\n");
std::cout << "Expected output for " << path << " (section " << path_section printf("Expected output for %s (section %s)\n:%s\n", path.c_str(),
<< "):" << std::endl; path_section.c_str(), joined_expected_output.c_str());
std::cout << joined_expected_output << std::endl; printf("Actual output for %s (section %s)\n:%s\n", path.c_str(),
std::cout << "Actual output for " << path << " (section " << path_section path_section.c_str(), joined_actual_output.c_str());
<< "):" << std::endl;
std::cout << joined_actual_output << std::endl;
std::cout << std::endl;
} }
void VerifySerializeToFrom(IndexFile* file) { void VerifySerializeToFrom(IndexFile* file) {
@ -173,7 +198,7 @@ void VerifySerializeToFrom(IndexFile* file) {
std::nullopt /*expected_version*/); std::nullopt /*expected_version*/);
std::string actual = result->ToString(); std::string actual = result->ToString();
if (expected != actual) { if (expected != actual) {
std::cerr << "Serialization failure" << std::endl; fprintf(stderr, "Serialization failure\n");
assert(false); assert(false);
} }
} }
@ -186,7 +211,7 @@ std::string FindExpectedOutputForFilename(
return entry.second; return entry.second;
} }
std::cerr << "Couldn't find expected output for " << filename << std::endl; fprintf(stderr, "Couldn't find expected output for %s\n", filename.c_str());
getchar(); getchar();
getchar(); getchar();
return "{}"; return "{}";
@ -203,16 +228,17 @@ IndexFile* FindDbForPathEnding(
} }
bool RunIndexTests(const std::string& filter_path, bool enable_update) { bool RunIndexTests(const std::string& filter_path, bool enable_update) {
SetTestOutputMode(); gTestOutputMode = true;
// Index tests change based on the version of clang used. // Index tests change based on the version of clang used.
static constexpr const char* kRequiredClangVersion = static const char kRequiredClangVersion[] =
"clang version 6.0.0 (tags/RELEASE_600/final)"; "clang version 6.0.0 (tags/RELEASE_600/final)";
if (GetClangVersion() != kRequiredClangVersion && if (GetClangVersion() != kRequiredClangVersion &&
GetClangVersion().find("trunk") == std::string::npos) { GetClangVersion().find("trunk") == std::string::npos) {
std::cerr << "Index tests must be run using clang version \"" fprintf(stderr,
<< kRequiredClangVersion << "\" (ccls is running with \"" "Index tests must be run using clang version %s, ccls is running "
<< GetClangVersion() << "\")" << std::endl; "with %s\n",
kRequiredClangVersion, GetClangVersion().c_str());
return false; return false;
} }
@ -221,31 +247,36 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
// FIXME: show diagnostics in STL/headers when running tests. At the moment // FIXME: show diagnostics in STL/headers when running tests. At the moment
// this can be done by constructing ClangIndex index(1, 1); // this can be done by constructing ClangIndex index(1, 1);
ClangIndex index; ClangIndex index;
for (std::string path : GetFilesInFolder("index_tests", true /*recursive*/, GetFilesInFolder(
true /*add_folder_to_path*/)) { "index_tests", true /*recursive*/, true /*add_folder_to_path*/,
[&](const std::string& path) {
bool is_fail_allowed = false; bool is_fail_allowed = false;
if (EndsWithAny(path, {".m", ".mm"})) { if (EndsWithAny(path, {".m", ".mm"})) {
#ifndef __APPLE__ #ifndef __APPLE__
std::cout << "Skipping \"" << path << "\" since this platform does not " return;
<< "support running Objective-C tests." << std::endl;
continue;
#endif #endif
// objective-c tests are often not updated right away. do not bring down // objective-c tests are often not updated right away. do not bring
// down
// CI if they fail. // CI if they fail.
if (!enable_update) if (!enable_update)
is_fail_allowed = true; is_fail_allowed = true;
} }
if (path.find(filter_path) == std::string::npos) if (path.find(filter_path) == std::string::npos)
continue; return;
if (!filter_path.empty()) if (!filter_path.empty())
std::cout << "Running " << path << std::endl; printf("Running %s\n", path.c_str());
// Parse expected output from the test, parse it into JSON document. // Parse expected output from the test, parse it into JSON document.
std::vector<std::string> lines_with_endings = ReadFileLines(path); std::vector<std::string> lines_with_endings;
{
std::ifstream fin(path);
for (std::string line; std::getline(fin, line);)
lines_with_endings.push_back(line);
}
TextReplacer text_replacer; TextReplacer text_replacer;
std::vector<std::string> flags; std::vector<std::string> flags;
std::unordered_map<std::string, std::string> all_expected_output; std::unordered_map<std::string, std::string> all_expected_output;
@ -253,14 +284,9 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
&all_expected_output); &all_expected_output);
// Build flags. // Build flags.
bool had_extra_flags = !flags.empty();
if (!AnyStartsWith(flags, "-x")) if (!AnyStartsWith(flags, "-x"))
flags.push_back("-xc++"); flags.push_back("-xc++");
flags.push_back("-resource-dir=" + GetDefaultResourceDirectory()); flags.push_back("-resource-dir=" + GetDefaultResourceDirectory());
if (had_extra_flags) {
std::cout << "For " << path << std::endl;
std::cout << " flags: " << StringJoin(flags) << std::endl;
}
flags.push_back(path); flags.push_back(path);
// Run test. // Run test.
@ -283,34 +309,32 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
return path.substr(last_index + 1); return path.substr(last_index + 1);
}; };
auto severity_to_string = [](const lsDiagnosticSeverity& severity) {
switch (severity) {
case lsDiagnosticSeverity::Error:
return "error ";
case lsDiagnosticSeverity::Warning:
return "warning ";
case lsDiagnosticSeverity::Information:
return "information ";
case lsDiagnosticSeverity::Hint:
return "hint ";
}
assert(false && "not reached");
return "";
};
// Get output from index operation. // Get output from index operation.
IndexFile* db = FindDbForPathEnding(expected_path, dbs); IndexFile* db = FindDbForPathEnding(expected_path, dbs);
assert(db); assert(db);
if (!db->diagnostics_.empty()) { if (!db->diagnostics_.empty()) {
std::cout << "For " << path << std::endl; printf("For %s\n", path.c_str());
for (const lsDiagnostic& diagnostic : db->diagnostics_) { for (const lsDiagnostic& diagnostic : db->diagnostics_) {
std::cout << " "; printf(" ");
if (diagnostic.severity) if (diagnostic.severity)
std::cout << severity_to_string(*diagnostic.severity); switch (*diagnostic.severity) {
std::cout << basename(db->path) << ":" case lsDiagnosticSeverity::Error:
<< diagnostic.range.start.ToString() << "-" printf("error ");
<< diagnostic.range.end.ToString() << ": " break;
<< diagnostic.message << std::endl; case lsDiagnosticSeverity::Warning:
printf("warning ");
break;
case lsDiagnosticSeverity::Information:
printf("information ");
break;
case lsDiagnosticSeverity::Hint:
printf("hint ");
break;
}
printf("%s:%s-%s:%s\n", basename(db->path).c_str(),
diagnostic.range.start.ToString().c_str(),
diagnostic.range.end.ToString().c_str(),
diagnostic.message.c_str());
} }
} }
std::string actual_output = "{}"; std::string actual_output = "{}";
@ -333,11 +357,11 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
if (!is_fail_allowed) if (!is_fail_allowed)
success = false; success = false;
DiffDocuments(path, expected_path, expected, actual); DiffDocuments(path, expected_path, expected, actual);
std::cout << std::endl; puts("\n");
std::cout << std::endl;
if (enable_update) { if (enable_update) {
std::cout printf(
<< "[Enter to continue - type u to update test, a to update all]"; "[Enter to continue - type u to update test, a to update "
"all]");
char c = 'u'; char c = 'u';
if (!update_all) { if (!update_all) {
c = getchar(); c = getchar();
@ -348,14 +372,16 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
update_all = true; update_all = true;
if (update_all || c == 'u') { if (update_all || c == 'u') {
// Note: we use |entry.second| instead of |expected_output| because // Note: we use |entry.second| instead of |expected_output|
// because
// |expected_output| has had text replacements applied. // |expected_output| has had text replacements applied.
UpdateTestExpectation(path, entry.second, ToString(actual) + "\n"); UpdateTestExpectation(path, entry.second,
} ToString(actual) + "\n");
} }
} }
} }
} }
});
return success; return success;
} }

View File

@ -1,6 +1,5 @@
#include "utils.h" #include "utils.h"
#include "filesystem.hh"
#include "platform.h" #include "platform.h"
#include <doctest/doctest.h> #include <doctest/doctest.h>
@ -12,12 +11,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <fstream>
#include <functional> #include <functional>
#include <queue>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map> #include <unordered_map>
using namespace std::placeholders; using namespace std::placeholders;
@ -83,26 +77,6 @@ bool FindAnyPartial(const std::string& value,
}); });
} }
std::string GetDirName(std::string path) {
if (path.size() && path.back() == '/')
path.pop_back();
size_t last_slash = path.find_last_of('/');
if (last_slash == std::string::npos)
return ".";
if (last_slash == 0)
return "/";
return path.substr(0, last_slash);
}
std::string GetBaseName(const std::string& path) {
return fs::path(path).filename();
}
std::string StripFileType(const std::string& path) {
fs::path p(path);
return p.parent_path() / p.stem();
}
std::vector<std::string> SplitString(const std::string& str, std::vector<std::string> SplitString(const std::string& str,
const std::string& delimiter) { const std::string& delimiter) {
// http://stackoverflow.com/a/13172514 // http://stackoverflow.com/a/13172514
@ -132,54 +106,6 @@ std::string LowerPathIfInsensitive(const std::string& path) {
#endif #endif
} }
static void GetFilesInFolderHelper(
std::string folder,
bool recursive,
std::string output_prefix,
const std::function<void(const std::string&)>& handler) {
std::queue<std::pair<fs::path, fs::path>> q;
q.emplace(fs::path(folder), fs::path(output_prefix));
while (!q.empty()) {
for (auto it = fs::directory_iterator(q.front().first); it != fs::directory_iterator(); ++it) {
auto path = it->path();
std::string filename = path.filename();
if (filename[0] != '.' || filename == ".ccls") {
fs::file_status status = it->symlink_status();
if (fs::is_regular_file(status))
handler(q.front().second / filename);
else if (fs::is_directory(status) || fs::is_symlink(status)) {
if (recursive) {
std::string child_dir = q.front().second / filename;
if (fs::is_directory(status))
q.push(make_pair(path, child_dir));
}
}
}
}
q.pop();
}
}
std::vector<std::string> GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path) {
EnsureEndsInSlash(folder);
std::vector<std::string> result;
GetFilesInFolderHelper(
folder, recursive, add_folder_to_path ? folder : "",
[&result](const std::string& path) { result.push_back(path); });
return result;
}
void GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path,
const std::function<void(const std::string&)>& handler) {
EnsureEndsInSlash(folder);
GetFilesInFolderHelper(folder, recursive, add_folder_to_path ? folder : "",
handler);
}
void EnsureEndsInSlash(std::string& path) { void EnsureEndsInSlash(std::string& path) {
if (path.empty() || path[path.size() - 1] != '/') if (path.empty() || path[path.size() - 1] != '/')
path += '/'; path += '/';
@ -195,10 +121,6 @@ std::string EscapeFileName(std::string path) {
return path; return path;
} }
bool FileExists(const std::string& filename) {
return fs::exists(filename);
}
std::optional<std::string> ReadContent(const std::string& filename) { std::optional<std::string> ReadContent(const std::string& filename) {
LOG_S(INFO) << "Reading " << filename; LOG_S(INFO) << "Reading " << filename;
char buf[4096]; char buf[4096];
@ -211,41 +133,6 @@ std::optional<std::string> ReadContent(const std::string& filename) {
return ret; return ret;
} }
std::vector<std::string> ReadFileLines(std::string filename) {
std::vector<std::string> result;
std::ifstream fin(filename);
for (std::string line; std::getline(fin, line);)
result.push_back(line);
return result;
}
std::vector<std::string> ToLines(const std::string& content) {
std::vector<std::string> result;
std::istringstream lines(content);
std::string line;
while (getline(lines, line))
result.push_back(line);
return result;
}
std::string TextReplacer::Apply(const std::string& content) {
std::string result = content;
for (const Replacement& replacement : replacements) {
while (true) {
size_t idx = result.find(replacement.from);
if (idx == std::string::npos)
break;
result.replace(result.begin() + idx,
result.begin() + idx + replacement.from.size(),
replacement.to);
}
}
return result;
}
void WriteToFile(const std::string& filename, const std::string& content) { void WriteToFile(const std::string& filename, const std::string& content) {
FILE* f = fopen(filename.c_str(), "wb"); FILE* f = fopen(filename.c_str(), "wb");
if (!f || fwrite(content.c_str(), content.size(), 1, f) != 1) { if (!f || fwrite(content.c_str(), content.size(), 1, f) != 1) {
@ -278,19 +165,3 @@ std::string GetDefaultResourceDirectory() {
return NormalizePath(result); return NormalizePath(result);
} }
void StartThread(const std::string& thread_name, std::function<void()> entry) {
new std::thread([thread_name, entry]() {
SetCurrentThreadName(thread_name);
entry();
});
}
TEST_SUITE("StripFileType") {
TEST_CASE("all") {
REQUIRE(StripFileType("") == "");
REQUIRE(StripFileType("bar") == "bar");
REQUIRE(StripFileType("bar.cc") == "bar");
REQUIRE(StripFileType("foo/bar.cc") == "foo/bar");
}
}

View File

@ -4,7 +4,6 @@
#include <string_view> #include <string_view>
#include <algorithm> #include <algorithm>
#include <functional>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <string> #include <string>
@ -23,13 +22,6 @@ bool StartsWithAny(std::string_view s, const std::vector<std::string>& ps);
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss); bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss);
bool FindAnyPartial(const std::string& value, bool FindAnyPartial(const std::string& value,
const std::vector<std::string>& values); const std::vector<std::string>& values);
// Returns the dirname of |path|, i.e. "foo/bar.cc" => "foo", "foo" => ".",
// "/foo" => "/".
std::string GetDirName(std::string path);
// Returns the basename of |path|, ie, "foo/bar.cc" => "bar.cc".
std::string GetBaseName(const std::string& path);
// Returns |path| without the filetype, ie, "foo/bar.cc" => "foo/bar".
std::string StripFileType(const std::string& path);
std::vector<std::string> SplitString(const std::string& str, std::vector<std::string> SplitString(const std::string& str,
const std::string& delimiter); const std::string& delimiter);
@ -62,15 +54,6 @@ bool ContainsValue(const TCollection& collection, const TValue& value) {
return collection.find(value) != collection.end(); return collection.find(value) != collection.end();
} }
// Finds all files in the given folder. This is recursive.
std::vector<std::string> GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path);
void GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path,
const std::function<void(const std::string&)>& handler);
// Ensures that |path| ends in a slash. // Ensures that |path| ends in a slash.
void EnsureEndsInSlash(std::string& path); void EnsureEndsInSlash(std::string& path);
@ -78,22 +61,7 @@ void EnsureEndsInSlash(std::string& path);
// e.g. foo/bar.c => foo_bar.c // e.g. foo/bar.c => foo_bar.c
std::string EscapeFileName(std::string path); std::string EscapeFileName(std::string path);
// FIXME: Move ReadContent into ICacheManager?
bool FileExists(const std::string& filename);
std::optional<std::string> ReadContent(const std::string& filename); std::optional<std::string> ReadContent(const std::string& filename);
std::vector<std::string> ReadFileLines(std::string filename);
std::vector<std::string> ToLines(const std::string& content);
struct TextReplacer {
struct Replacement {
std::string from;
std::string to;
};
std::vector<Replacement> replacements;
std::string Apply(const std::string& content);
};
void WriteToFile(const std::string& filename, const std::string& content); void WriteToFile(const std::string& filename, const std::string& content);
@ -149,5 +117,3 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
} }
std::string GetDefaultResourceDirectory(); std::string GetDefaultResourceDirectory();
void StartThread(const std::string& thread_name, std::function<void()> entry);

View File

@ -9,6 +9,7 @@
#include <algorithm> #include <algorithm>
#include <climits> #include <climits>
#include <numeric> #include <numeric>
#include <sstream>
namespace { namespace {
@ -38,6 +39,15 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
return result; return result;
} }
std::vector<std::string> ToLines(const std::string& content) {
std::vector<std::string> result;
std::istringstream lines(content);
std::string line;
while (getline(lines, line))
result.push_back(line);
return result;
}
// Computes the edit distance of strings [a,a+la) and [b,b+lb) with Eugene W. // Computes the edit distance of strings [a,a+la) and [b,b+lb) with Eugene W.
// Myers' O(ND) diff algorithm. // Myers' O(ND) diff algorithm.
// Costs: insertion=1, deletion=1, no substitution. // Costs: insertion=1, deletion=1, no substitution.