Compare commits

..

11 Commits

Author SHA1 Message Date
Owen Mansel-Chan
0df9aac69c Merge pull request #21988 from owen-mc/ql/convert-qlref-tests-inline-expectations
QL: Convert qlref tests to inline expectations
2026-06-15 21:09:44 +01:00
Owen Mansel-Chan
78d95719a5 Do not convert test that is example of not using inline expectations 2026-06-15 16:18:24 +01:00
Asger F
7039c4a2be Merge pull request #21981 from asgerf/yeast/comments
Yeast/Unified: Extract comments
2026-06-15 15:25:35 +02:00
Michael Nebel
746631d3dc Merge pull request #21989 from michaelnebel/csharp/compoundmad
C#: Add models as data tests for compound assignment operators.
2026-06-15 14:57:04 +02:00
Michael Nebel
175c4f1b0d C#: Add models as data tests for compound assignment operators. 2026-06-15 13:26:39 +02:00
Owen Mansel-Chan
4ad3a44aab QL: Convert qlref tests to inline expectations 2026-06-15 11:15:16 +01:00
Asger F
6000c18c24 Unified: also QLDoc for unified.qll 2026-06-12 16:48:25 +02:00
Asger F
e81a3bcbc3 Unified: Add QLDoc 2026-06-12 16:47:06 +02:00
Asger F
7d6d5bfb4a Unified: add test for comments 2026-06-12 16:36:33 +02:00
Asger F
f83adb55ce Unified: regenerate AST 2026-06-12 16:33:51 +02:00
Asger F
5608369abe Extract trivia tokens from original parse tree 2026-06-12 16:32:57 +02:00
79 changed files with 443 additions and 304 deletions

View File

@@ -442,4 +442,31 @@ namespace My.Qltest
static void Sink(object o) { }
}
// Test operator overloads
public class N
{
public void operator +=(N y) => throw null;
public void operator checked +=(N y) => throw null;
public void M1(N n)
{
var n0 = new N();
n += n0;
Sink(n);
}
public void M2(N n)
{
var n0 = new N();
checked
{
n += n0;
}
Sink(n);
}
static void Sink(object o) { }
}
}

View File

@@ -32,14 +32,16 @@ models
| 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated |
| 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual |
| 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated |
| 34 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 35 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
| 34 | Summary: My.Qltest; N; false; op_AdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual |
| 35 | Summary: My.Qltest; N; false; op_CheckedAdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 42 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 43 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
edges
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | |
@@ -162,69 +164,77 @@ edges
| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:37 |
| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:37 |
| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 |
| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 |
| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 |
| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 |
| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 |
| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:42 |
| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 |
| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:42 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | provenance | |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | provenance | MaD:34 |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | provenance | |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | provenance | MaD:35 |
nodes
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
@@ -443,6 +453,16 @@ nodes
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | semmle.label | access to parameter n |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | semmle.label | access to parameter n |
subpaths
| ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object |
invalidModelRow
@@ -489,3 +509,5 @@ invalidModelRow
| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | $@ | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | object creation of type N : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | $@ | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | object creation of type N : N |

View File

@@ -53,6 +53,8 @@ extensions:
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"]
- ["My.Qltest", "N", false, "op_AdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["My.Qltest", "N", false, "op_CheckedAdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- addsTo:
pack: codeql/csharp-all

View File

@@ -1,5 +1,5 @@
string foo() {
result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // BAD
result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // $ Alert // BAD
or
result = concat(string x | x = [0 .. 10].toString() | x, ", " order by x desc) // GOOD
}

View File

@@ -1 +1,2 @@
queries/bugs/OrderByConst.ql
query: queries/bugs/OrderByConst.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/bugs/SumWithoutDomain.ql
query: queries/bugs/SumWithoutDomain.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,6 +1,6 @@
// Result is 3 and not 4
int foo() {
result = sum([1, 1, 2]) // <- Alert here
result = sum([1, 1, 2]) // $ Alert // <- Alert here
}
// Ok - false negative

View File

@@ -1 +1,2 @@
queries/overlay/InlineOverlayCaller.ql
query: queries/overlay/InlineOverlayCaller.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,7 +4,7 @@ module;
import ql
pragma[inline]
predicate foo(int x) { x = 42 }
predicate foo(int x) { x = 42 } // $ Alert
overlay[caller]
pragma[inline]

View File

@@ -1 +1,2 @@
queries/performance/AbstractClassImport.ql
query: queries/performance/AbstractClassImport.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,4 @@
import ql
import AbstractClassImportTest2
abstract class Base extends AstNode { }
abstract class Base extends AstNode { } // $ Alert

View File

@@ -1 +1,2 @@
queries/performance/MissingNoinline.ql
query: queries/performance/MissingNoinline.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -5,7 +5,7 @@ import ql
*
* This predicate exists to fix a join order.
*/
predicate missingNoInline(AddExpr add, Expr e1, Expr e2) {
predicate missingNoInline(AddExpr add, Expr e1, Expr e2) { // $ Alert
// BAD
add.getLeftOperand() = e1 and
add.getRightOperand() = e2

View File

@@ -13,21 +13,21 @@ class MyStr extends string {
predicate bad1(Big b) {
b.toString().matches("%foo")
or
any()
any() // $ Alert
}
int bad2() {
exists(Big big, Small small |
result = big.toString().toInt()
or
result = small.toString().toInt()
result = small.toString().toInt() // $ Alert
)
}
float bad3(Big t) {
result = [1 .. 10].toString().toFloat() or
result = [11 .. 20].toString().toFloat() or
result = t.toString().toFloat() or
result = t.toString().toFloat() or // $ Alert
result = [21 .. 30].toString().toFloat()
}
@@ -50,7 +50,7 @@ predicate bad4(Big fromType, Big toType) {
or
fromType.toString().matches("%foo")
or
helper(toType, fromType)
helper(toType, fromType) // $ Alert
}
predicate good2(Big t) {
@@ -71,7 +71,7 @@ predicate mixed1(Big good, Small small) {
small.toString().matches("%foo") and
// the use of good is fine, the comparison further up binds it.
// the same is not true for bad.
(bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and
(bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and // $ Alert
small.toString().regexpMatch(".*foo")
)
}
@@ -112,7 +112,7 @@ predicate good5(Big bb, Big v, boolean certain) {
)
}
predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() }
predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() } // $ Alert
pragma[inline]
predicate good5(Big a, Big b) {
@@ -126,12 +126,12 @@ predicate bad6(Big a) {
(
a.toString().matches("%foo") // bad
or
any()
any() // $ Alert
) and
(
a.toString().matches("%foo") // also bad
or
any()
any() // $ Alert
)
}
@@ -163,7 +163,7 @@ class HasField extends Big {
HasField() {
field = this
or
this.toString().matches("%foo") // <- field only defined here.
this.toString().matches("%foo") // $ Alert // <- field only defined here.
}
Big getField() { result = field }

View File

@@ -1 +1,2 @@
queries/performance/VarUnusedInDisjunct.ql
query: queries/performance/VarUnusedInDisjunct.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/AcronymsShouldBeCamelCase.ql
query: queries/style/AcronymsShouldBeCamelCase.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,13 +1,13 @@
// BAD
predicate isXML() { any() }
predicate isXML() { any() } // $ Alert
// GOOD [ AES is exceptional ]
predicate isAES() { any() }
// BAD
newtype TXMLElements =
newtype TXMLElements = // $ Alert
TXmlElement() or // GOOD
TXMLElement() // BAD
TXMLElement() // $ Alert // BAD
// GOOD
newtype TIRFunction = MkIRFunction()

View File

@@ -1 +1,2 @@
queries/style/CouldBeCast.ql
query: queries/style/CouldBeCast.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,20 +1,20 @@
bindingset[i]
predicate foo(int i) {
exists(Even j | j = i) // NOT OK
exists(Even j | j = i) // $ Alert // NOT OK
or
exists(Even j | j = i | j % 4 = 0) // OK
or
any(Even j | j = i) = 2 // NOT OK
any(Even j | j = i) = 2 // $ Alert // NOT OK
or
any(Even j | j = i | j) = 2 // NOT OK
any(Even j | j = i | j) = 2 // $ Alert // NOT OK
or
any(Even j | j = i | j * 2) = 4 // OK
or
any(Even j | j = i and j % 4 = 0 | j) = 4 // OK
or
any(int j | j = i) = 2 // NOT OK
any(int j | j = i) = 2 // $ Alert // NOT OK
or
exists(int j | j = i) // NOT OK
exists(int j | j = i) // $ Alert // NOT OK
}
class Even extends int {

View File

@@ -1 +1,2 @@
queries/style/DataFlowConfigModuleNaming.ql
query: queries/style/DataFlowConfigModuleNaming.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,14 +8,14 @@ module EmptyConfig implements DataFlow::ConfigSig {
}
// BAD - does not end with "Config"
module EmptyConfiguration implements DataFlow::ConfigSig {
module EmptyConfiguration implements DataFlow::ConfigSig { // $ Alert
predicate isSource(DataFlow::Node src) { none() }
predicate isSink(DataFlow::Node sink) { none() }
}
// BAD - does not end with "Config"
module EmptyFlow implements DataFlow::ConfigSig {
module EmptyFlow implements DataFlow::ConfigSig { // $ Alert
predicate isSource(DataFlow::Node src) { none() }
predicate isSink(DataFlow::Node sink) { none() }

View File

@@ -1 +1,2 @@
queries/style/DeadCode.ql
query: queries/style/DeadCode.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,11 +1,11 @@
import ql
private module Mixed {
private predicate dead1() { none() }
private predicate dead1() { none() } // $ Alert
predicate alive1() { none() }
predicate dead2() { none() }
predicate dead2() { none() } // $ Alert
}
predicate usesAlive() { Mixed::alive1() }
@@ -43,7 +43,7 @@ private module Input1 implements InputSig {
predicate foo() { any() }
}
private module Input2 implements InputSig {
private module Input2 implements InputSig { // $ Alert
predicate foo() { any() }
}
@@ -53,7 +53,7 @@ private module Input3 implements InputSig {
module M1 = ParameterizedModule<Input1>;
private module M2 = ParameterizedModule<Input2>;
private module M2 = ParameterizedModule<Input2>; // $ Alert
import ParameterizedModule<Input3>
@@ -65,7 +65,7 @@ private class CImpl1 extends AstNode { }
final class CPublic1 = CImpl1;
private class CImpl2 extends AstNode { }
private class CImpl2 extends AstNode { } // $ Alert
overlay[discard_entity]
private predicate discard(@foo x) { any() }

View File

@@ -1,5 +1,5 @@
class C1 extends int {
int field; // BAD
int field; // $ Alert // BAD
C1() {
this = field and

View File

@@ -1 +1,2 @@
queries/style/FieldOnlyUsedInCharPred.ql
query: queries/style/FieldOnlyUsedInCharPred.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -7,5 +7,5 @@ class Foo extends string {
string getBarWithThis() { result = this.getBar() }
string getBarWithoutThis() { result = getBar() }
string getBarWithoutThis() { result = getBar() } // $ Alert
}

View File

@@ -5,5 +5,5 @@ class Foo extends string {
string getBar() { result = "bar" }
string getBarWithoutThis() { result = getBar() }
string getBarWithoutThis() { result = getBar() } // $ Alert
}

View File

@@ -1 +1,2 @@
queries/style/ImplicitThis.ql
query: queries/style/ImplicitThis.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -2,7 +2,7 @@
predicate test1(int param1, int param2, int param3) { none() } // OK
/** `param1`, `par2` */
predicate test2(int param1, int param2) { none() } // NOT OK - `par2` is not a parameter, and `param2` has no documentation
predicate test2(int param1, int param2) { none() } // $ Alert // NOT OK - `par2` is not a parameter, and `param2` has no documentation
/** `param1`, `par2 + par3` */
predicate test3(int param1, int par2, int par3) { none() } // OK
@@ -11,4 +11,4 @@ predicate test3(int param1, int par2, int par3) { none() } // OK
predicate test4(int param1, int param2) { none() } // OK - the QLDoc mentions none of the parameters, that's OK
/** the param1 parameter is mentioned in a non-code block, but the `par2` parameter is misspelled */
predicate test5(int param1, int param2) { none() } // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled
predicate test5(int param1, int param2) { none() } // $ Alert // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled

View File

@@ -1 +1,2 @@
queries/style/MissingParameterInQlDoc.ql
query: queries/style/MissingParameterInQlDoc.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/MissingQualityMetadata.ql
query: queries/style/MissingQualityMetadata.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* maintainability
* error-handling
*/
*/ // $ Alert
import ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* maintainability
* reliability
*/
*/ // $ Alert
import ql

View File

@@ -7,7 +7,7 @@
* @id ql/quality-query-test
* @tags quality
* someothertag
*/
*/ // $ Alert
import ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* reliability
* readability
*/
*/ // $ Alert
import ql

View File

@@ -1 +1,2 @@
queries/style/MissingSecurityMetadata.ql
query: queries/style/MissingSecurityMetadata.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -7,7 +7,7 @@
* @precision very-high
* @id ql/some-query
* @tags quality
*/
*/ // $ Alert
import ql

View File

@@ -7,7 +7,7 @@
* @id ql/some-query
* @tags quality
* security
*/
*/ // $ Alert
import ql

View File

@@ -1 +1,2 @@
queries/style/Misspelling.ql
query: queries/style/Misspelling.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,13 +1,13 @@
/**
* A string that's deliberately mispelled (and so is that last word).
*/
class PublicallyAccessible extends string {
int numOccurences; // should be 'occurrences'
*/ // $ Alert
class PublicallyAccessible extends string { // $ Alert
int numOccurences; // $ Alert // should be 'occurrences'
PublicallyAccessible() { this = "publically" and numOccurences = 123 }
// should be argument
predicate hasAgrument() { none() }
predicate hasAgrument() { none() } // $ Alert
int getNum() { result = numOccurences }
}
@@ -15,8 +15,8 @@ class PublicallyAccessible extends string {
/**
* A class whose name contains a British-English spelling.
* And here's the word 'colour'.
*/
class AnalysedInt extends int {
*/ // $ Alert
class AnalysedInt extends int { // $ Alert
AnalysedInt() { this = 7 }
// 'analyses' should not be flagged

View File

@@ -1,13 +1,13 @@
/*
* This should be QLDoc.
*/
*/ // $ Alert
/**
* this is fine
*/
predicate foo() { any() }
/* Note: this is bad. */
/* Note: this is bad. */ // $ Alert
class Foo extends string {
Foo() { this = "FOo" }
}

View File

@@ -1 +1,2 @@
queries/style/NonDocBlock.ql
query: queries/style/NonDocBlock.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/OmittableExists.ql
query: queries/style/OmittableExists.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -17,7 +17,7 @@ class Location extends @location_default {
}
predicate test() {
exists(int i | aPredicate(i)) // BAD
exists(int i | aPredicate(i)) // $ Alert // BAD
or
exists(int i | aPredicate(i) or anotherPredicate(i)) // BAD [NOT DETECTED]
or

View File

@@ -1 +1 @@
| Test3.qlref:1:1:1:22 | query: ... uery.ql | Query test does not use inline test expectations. |
| Test3.qlref:1:1:1:23 | query: ... uery.ql | Query test does not use inline test expectations. |

View File

@@ -1 +1 @@
query: ProblemQuery.ql
query: ProblemQuery.ql

View File

@@ -2,10 +2,10 @@ class Foo extends string {
Foo() { this = "Foo" }
}
predicate test(Foo f) { f.(Foo).toString() = "X" }
predicate test(Foo f) { f.(Foo).toString() = "X" } // $ Alert
predicate test2(Foo a, Foo b) { a.(Foo) = b }
predicate test2(Foo a, Foo b) { a.(Foo) = b } // $ Alert
predicate called(Foo a) { a.toString() = "X" }
predicate test3(string s) { called(s.(Foo)) }
predicate test3(string s) { called(s.(Foo)) } // $ Alert

View File

@@ -1 +1,2 @@
queries/style/RedundantCast.ql
query: queries/style/RedundantCast.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,2 +1,2 @@
import folder.A
import folder.A // $ Alert
import folder.B

View File

@@ -1 +1,2 @@
queries/style/RedundantImport.ql
query: queries/style/RedundantImport.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -6,7 +6,7 @@ module Test1 {
}
class Bar extends Foo {
override Foo pred() { result = Foo.super.pred() } // BAD
override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD
}
}
@@ -18,7 +18,7 @@ module Test2 {
}
class Bar extends Foo {
override Foo pred() { result = super.pred() } // BAD
override Foo pred() { result = super.pred() } // $ Alert // BAD
}
}
@@ -107,7 +107,7 @@ module Test8 {
}
class Bar extends Foo {
override predicate pred(Foo f) { super.pred(f) } // BAD
override predicate pred(Foo f) { super.pred(f) } // $ Alert // BAD
}
}
@@ -121,15 +121,15 @@ module Test9 {
class Bar extends Foo {
Bar() { this = 1 }
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Baz1 extends Foo, Bar {
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Baz2 extends Foo, Baz1 {
override Foo pred() { Baz1.super.pred() = result } // BAD
override Foo pred() { Baz1.super.pred() = result } // $ Alert // BAD
}
}
@@ -147,7 +147,7 @@ module Test10 {
}
class Baz1 extends Foo, Bar {
override Foo pred() { result = Foo.super.pred() } // BAD
override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD
}
}
@@ -161,19 +161,19 @@ module Test11 {
class Bar1 extends Foo {
Bar1() { this = [1 .. 3] }
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Bar2 extends Foo, Bar1 {
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Bar3 extends Foo, Bar2 {
override Foo pred() { Bar2.super.pred() = result } // BAD
override Foo pred() { Bar2.super.pred() = result } // $ Alert // BAD
}
class Bar4 extends Bar2, Bar3 {
override Foo pred() { result = Bar2.super.pred() } // BAD
override Foo pred() { result = Bar2.super.pred() } // $ Alert // BAD
}
class Bar5 extends Foo {

View File

@@ -1 +1,2 @@
queries/style/RedundantOverride.ql
query: queries/style/RedundantOverride.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/SwappedParameterNames.ql
query: queries/style/SwappedParameterNames.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -9,5 +9,5 @@ class Correct extends Sup {
}
class Wrong extends Sup {
override predicate step(Expr succ, Expr pred) { none() } // <- swapped parameter names
override predicate step(Expr succ, Expr pred) { none() } // $ Alert // <- swapped parameter names
}

View File

@@ -4,7 +4,7 @@ class Range extends string {
string getAChild() { result = "test" }
}
class Inst extends string {
class Inst extends string { // $ Alert
Range range;
Inst() { this = range }
@@ -12,13 +12,13 @@ class Inst extends string {
string getAChild() { result = range.getAChild() }
}
class Inst2 extends string {
class Inst2 extends string { // $ Alert
Inst2() { this instanceof Range }
string getAChild() { result = this.(Range).getAChild() }
}
class Inst3 extends string {
class Inst3 extends string { // $ Alert
Range range;
Inst3() { this = range }
@@ -26,6 +26,6 @@ class Inst3 extends string {
Range getRange() { result = range }
}
class Inst4 extends string {
class Inst4 extends string { // $ Alert
Inst4() { this instanceof Range }
}

View File

@@ -1 +1,2 @@
queries/style/UseInstanceofExtension.ql
query: queries/style/UseInstanceofExtension.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/UseSetLiteral.ql
query: queries/style/UseSetLiteral.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,7 +4,7 @@ predicate test1(int a) {
a = 1 or // BAD
a = 2 or
a = 3 or
a = 4
a = 4 // $ Alert
}
predicate test2(int a) {
@@ -30,7 +30,7 @@ predicate test5() {
test1(1) or // BAD
test1(2) or
test1(3) or
test1(4)
test1(4) // $ Alert
}
predicate test6() {
@@ -44,7 +44,7 @@ int test7() {
1 = result or // BAD
2 = result or
3 = result or
4 = result
4 = result // $ Alert
}
predicate test8() {
@@ -62,19 +62,19 @@ class MyTest8Class extends int {
this = 1 or // BAD
this = 2 or
this = 3 or
this = 4
this = 4 // $ Alert
) and
(
s = "1" or // BAD
s = "2" or
s = "3" or
s = "4"
s = "4" // $ Alert
) and
exists(float f |
f = 1.0 or // BAD
f = 1.5 or
f = 2.0 or
f = 2.5
f = 2.5 // $ Alert
)
}
@@ -89,7 +89,7 @@ predicate test9(MyTest8Class c) {
c.is(1) or // BAD
c.is(2) or
c.is(3) or
c.is(4)
c.is(4) // $ Alert
}
predicate test10(MyTest8Class c) {
@@ -133,5 +133,5 @@ predicate test14(int a) {
(a = 2 or a = 3)
or
a = 4
)
) // $ Alert
}

View File

@@ -1 +1,2 @@
queries/style/ValidatePredicateGetReturns.ql
query: queries/style/ValidatePredicateGetReturns.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,7 +1,7 @@
import ql
// NOT OK -- Predicate starts with "get" but does not return a value
predicate getValue() { none() }
predicate getValue() { none() } // $ Alert
// OK -- starts with get and returns a value
string getData() { result = "data" }
@@ -22,13 +22,13 @@ predicate getvalue() { none() }
predicate retrieveValue() { none() }
// NOT OK -- starts with get and does not return value
predicate getImplementation2() { none() }
predicate getImplementation2() { none() } // $ Alert
// NOT OK -- is an alias for a predicate which does not have a return value
predicate getAlias2 = getImplementation2/0;
predicate getAlias2 = getImplementation2/0; // $ Alert
// NOT OK -- starts with as and does not return value
predicate asValue() { none() }
predicate asValue() { none() } // $ Alert
// OK -- starts with as but followed by a lowercase letter, probably should be ignored
predicate assessment() { none() }
@@ -45,7 +45,7 @@ HiddenType getInjectableCompositeActionNode() {
predicate implementation4() { none() }
// NOT OK -- is an alias
predicate getAlias4 = implementation4/0;
predicate getAlias4 = implementation4/0; // $ Alert
// OK -- is an alias
predicate alias5 = implementation4/0;
@@ -58,7 +58,7 @@ predicate edge(int x, int y) { none() }
int getDistance(int x) = shortestDistances(root/0, edge/2)(_, x, result)
// NOT OK -- Higher-order predicate that does not return a value even though has 'get' in the name
predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y)
predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y) // $ Alert
// OK
predicate unresolvedAlias = unresolved/0;

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* The `else` branch of a `case` expression is no longer represented as a `StmtSequence` directly. Instead, a new `CaseElseBranch` AST node wraps the body (a `StmtSequence`). `CaseExpr.getElseBranch()` now returns a `CaseElseBranch`, and the body of the else branch can be accessed via `CaseElseBranch.getBody()`.

View File

@@ -377,18 +377,18 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
/**
* Gets the `n`th branch of this case expression, either a `WhenClause`, an
* `InClause`, or a `CaseElseBranch`.
* `InClause`, or a `StmtSequence`.
*/
final AstNode getBranch(int n) { result = super.getBranch(n) }
/**
* Gets a branch of this case expression, either a `WhenClause`, an
* `InClause`, or a `CaseElseBranch`.
* `InClause`, or a `StmtSequence`.
*/
final AstNode getABranch() { result = this.getBranch(_) }
/** Gets the `else` branch of this case expression, if any. */
final CaseElseBranch getElseBranch() { result = this.getABranch() }
final StmtSequence getElseBranch() { result = this.getABranch() }
/**
* Gets the number of branches of this case expression.
@@ -533,30 +533,6 @@ class InClause extends AstNode instanceof InClauseImpl {
}
}
/**
* An `else` branch of a `case` expression.
* ```rb
* case foo
* when 1 then puts "one"
* else puts "other"
* end
* ```
*/
class CaseElseBranch extends AstNode instanceof CaseElseBranchImpl {
final override string getAPrimaryQlClass() { result = "CaseElseBranch" }
/** Gets the body of this else branch. */
final Stmt getBody() { result = super.getBody() }
final override string toString() { result = "else ..." }
final override AstNode getAChild(string pred) {
result = AstNode.super.getAChild(pred)
or
pred = "getBody" and result = this.getBody()
}
}
/**
* A one-line pattern match using the `=>` operator. For example:
* ```rb

View File

@@ -113,9 +113,6 @@ private module Cached {
TBraceBlockSynth(Ast::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or
TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or
TBreakStmt(Ruby::Break g) or
TCaseElseBranchSynth(Ast::AstNode parent, int i) {
mkSynthChild(CaseElseBranchKind(), parent, i)
} or
TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or
TCaseExpr(Ruby::Case g) or
TCaseMatchReal(Ruby::CaseMatch g) or
@@ -403,15 +400,14 @@ private module Cached {
class TAstNodeSynth =
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
TBitwiseXorExprSynth or TBraceBlockSynth or TBodyStmtSynth or TBooleanLiteralSynth or
TCaseElseBranchSynth or TCaseMatchSynth or TClassVariableAccessSynth or
TConstantReadAccessSynth or TConstantWriteAccessSynth or TDivExprSynth or TElseSynth or
TExponentExprSynth or TGlobalVariableAccessSynth or TIfSynth or TInClauseSynth or
TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or
TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or
TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TNilLiteralSynth or
TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or
TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or TSubExprSynth or
TPairSynth or TSimpleSymbolLiteralSynth;
TCaseMatchSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or
TConstantWriteAccessSynth or TDivExprSynth or TElseSynth or TExponentExprSynth or
TGlobalVariableAccessSynth or TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or
TIntegerLiteralSynth or TLShiftExprSynth or TLocalVariableAccessSynth or
TLogicalAndExprSynth or TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or
TMulExprSynth or TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
TSimpleParameterSynth or TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or
TSubExprSynth or TPairSynth or TSimpleSymbolLiteralSynth;
/**
* Gets the underlying TreeSitter entity for a given AST node. This does not
@@ -602,8 +598,6 @@ private module Cached {
or
result = TBraceBlockSynth(parent, i)
or
result = TCaseElseBranchSynth(parent, i)
or
result = TCaseMatchSynth(parent, i)
or
result = TClassVariableAccessSynth(parent, i, _)
@@ -724,8 +718,6 @@ TAstNodeReal fromGenerated(Ruby::AstNode n) { n = toGenerated(result) }
class TCall = TMethodCall or TYieldCall;
class TCaseElseBranch = TCaseElseBranchSynth;
class TCaseMatch = TCaseMatchReal or TCaseMatchSynth;
class TCase = TCaseExpr or TCaseMatch;

View File

@@ -19,11 +19,8 @@ class CaseWhenClause extends CaseExprImpl, TCaseExpr {
final override Expr getValue() { toGenerated(result) = g.getValue() }
final override AstNode getBranch(int n) {
// When branches map directly to WhenClause nodes
toGenerated(result) = g.getChild(n) and not g.getChild(n) instanceof Ruby::Else
or
// The else branch is wrapped in a synthesized CaseElseBranch node
g.getChild(n) instanceof Ruby::Else and result = getSynthChild(this, n)
toGenerated(result) = g.getChild(n) or
toGenerated(result) = g.getChild(n)
}
}
@@ -37,8 +34,7 @@ class CaseMatch extends CaseExprImpl, TCaseMatchReal {
final override AstNode getBranch(int n) {
toGenerated(result) = g.getClauses(n)
or
// The else branch is wrapped in a synthesized CaseElseBranch node
n = count(g.getClauses(_)) and exists(g.getElse()) and result = getSynthChild(this, n)
n = count(g.getClauses(_)) and toGenerated(result) = g.getElse()
}
}
@@ -91,9 +87,3 @@ class InClauseSynth extends InClauseImpl, TInClauseSynth {
final override predicate hasUnlessCondition() { none() }
}
class CaseElseBranchImpl extends AstNode, TCaseElseBranch {
CaseElseBranchImpl() { this = TCaseElseBranchSynth(_, _) }
final Stmt getBody() { synthChild(this, 0, result) }
}

View File

@@ -22,7 +22,6 @@ newtype TSynthKind =
BodyStmtKind() or
BooleanLiteralKind(boolean value) { value = true or value = false } or
BraceBlockKind() or
CaseElseBranchKind() or
CaseMatchKind() or
ClassVariableAccessKind(ClassVariable v) or
DefinedExprKind() or
@@ -81,8 +80,6 @@ class SynthKind extends TSynthKind {
or
this = BraceBlockKind() and result = "BraceBlockKind"
or
this = CaseElseBranchKind() and result = "CaseElseBranchKind"
or
this = CaseMatchKind() and result = "CaseMatchKind"
or
this = ClassVariableAccessKind(_) and result = "ClassVariableAccessKind"
@@ -1843,7 +1840,7 @@ private module TestPatternDesugar {
or
child = SynthChild(InClauseKind()) and i = 1
or
child = SynthChild(CaseElseBranchKind()) and i = 2
child = SynthChild(ElseKind()) and i = 2
)
or
parent = TInClauseSynth(case, 1) and
@@ -1854,11 +1851,7 @@ private module TestPatternDesugar {
child = SynthChild(BooleanLiteralKind(true)) and i = 1
)
or
parent = TCaseElseBranchSynth(case, 2) and
child = SynthChild(ElseKind()) and
i = 0
or
parent = TElseSynth(TCaseElseBranchSynth(case, 2), 0) and
parent = TElseSynth(case, 2) and
child = SynthChild(BooleanLiteralKind(false)) and
i = 0
)
@@ -2001,61 +1994,3 @@ private module CallableBodySynthesis {
}
}
}
private module CaseElseBranchSynthesis {
pragma[nomagic]
private predicate caseElseBranchSynthesis(AstNode parent, int i, Child child) {
// Wrap the else branch of a real `case`/`when` expression
exists(Ruby::Case g, Ruby::Else elseNode, int elseIndex |
elseNode = g.getChild(elseIndex) and
(
// Create the CaseElseBranch wrapper node at the else index
parent = TCaseExpr(g) and
child = SynthChild(CaseElseBranchKind()) and
i = elseIndex
or
// The body of the CaseElseBranch is the Else node
parent = TCaseElseBranchSynth(TCaseExpr(g), elseIndex) and
child = RealChildRef(TElseReal(elseNode)) and
i = 0
)
)
or
// Wrap the else branch of a real `case`/`in` expression
exists(Ruby::CaseMatch g, Ruby::Else elseNode, int elseIndex |
elseNode = g.getElse() and
elseIndex = count(g.getClauses(_)) and
(
// Create the CaseElseBranch wrapper node at the else index
parent = TCaseMatchReal(g) and
child = SynthChild(CaseElseBranchKind()) and
i = elseIndex
or
// The body of the CaseElseBranch is the Else node
parent = TCaseElseBranchSynth(TCaseMatchReal(g), elseIndex) and
child = RealChildRef(TElseReal(elseNode)) and
i = 0
)
)
}
private class CaseElseBranchSynthesisImpl extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
caseElseBranchSynthesis(parent, i, child)
}
final override predicate location(AstNode n, Location l) {
// Give the CaseElseBranch the location of the underlying Else node
exists(Ruby::Case g, int elseIndex |
n = TCaseElseBranchSynth(TCaseExpr(g), elseIndex) and
l = g.getChild(elseIndex).getLocation()
)
or
exists(Ruby::CaseMatch g, int elseIndex |
elseIndex = count(g.getClauses(_)) and
n = TCaseElseBranchSynth(TCaseMatchReal(g), elseIndex) and
l = g.getElse().getLocation()
)
}
}
}

View File

@@ -498,16 +498,6 @@ module Trees {
}
}
private class CaseElseBranchTree extends ControlFlowTree instanceof CaseElseBranch {
final override predicate propagatesAbnormal(AstNode child) { child = super.getBody() }
final override predicate first(AstNode first) { first(super.getBody(), first) }
final override predicate last(AstNode last, Completion c) { last(super.getBody(), last, c) }
final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
}
private class PatternVariableAccessTree extends LocalVariableAccessTree instanceof LocalVariableWriteAccess,
CasePattern
{

View File

@@ -815,9 +815,8 @@ control/cases.rb:
# 11| getPattern: [LocalVariableAccess] d
# 11| getBody: [StmtSequence] then ...
# 12| getStmt: [IntegerLiteral] 200
# 13| getBranch/getElseBranch: [CaseElseBranch] else ...
# 13| getBody: [StmtSequence] else ...
# 14| getStmt: [IntegerLiteral] 300
# 13| getBranch/getElseBranch: [StmtSequence] else ...
# 14| getStmt: [IntegerLiteral] 300
# 18| getStmt: [CaseExpr] case ...
# 19| getBranch: [WhenClause] when ...
# 19| getPattern: [GTExpr] ... > ...
@@ -844,9 +843,8 @@ control/cases.rb:
# 27| getPattern: [IntegerLiteral] 5
# 27| getBody: [StmtSequence] then ...
# 27| getStmt: [BooleanLiteral] true
# 28| getBranch/getElseBranch: [CaseElseBranch] else ...
# 28| getBody: [StmtSequence] else ...
# 28| getStmt: [BooleanLiteral] false
# 28| getBranch/getElseBranch: [StmtSequence] else ...
# 28| getStmt: [BooleanLiteral] false
# 31| getStmt: [CaseExpr] case ...
# 31| getValue: [MethodCall] call to expr
# 31| getReceiver: [SelfVariableAccess] self
@@ -864,9 +862,8 @@ control/cases.rb:
# 34| getAnOperand/getArgument/getGreaterOperand/getRightOperand: [IntegerLiteral] 0
# 34| getBody: [StmtSequence] then ...
# 35| getStmt: [BooleanLiteral] true
# 36| getBranch/getElseBranch: [CaseElseBranch] else ...
# 36| getBody: [StmtSequence] else ...
# 36| getStmt: [BooleanLiteral] false
# 36| getBranch/getElseBranch: [StmtSequence] else ...
# 36| getStmt: [BooleanLiteral] false
# 39| getStmt: [CaseExpr] case ...
# 39| getValue: [MethodCall] call to expr
# 39| getReceiver: [SelfVariableAccess] self

View File

@@ -389,9 +389,8 @@ control/cases.rb:
# 160| getPrefixElement: [IntegerLiteral] 1
# 160| getPrefixElement: [IntegerLiteral] 2
# 160| getBody: [BooleanLiteral] true
# 160| getBranch/getElseBranch: [CaseElseBranch] else ...
# 160| getBody: [StmtSequence] else ...
# 160| getStmt: [BooleanLiteral] false
# 160| getBranch/getElseBranch: [StmtSequence] else ...
# 160| getStmt: [BooleanLiteral] false
# 162| [MatchPattern] ... => ...
# 162| getDesugared: [CaseExpr] case ...
# 162| getValue: [MethodCall] call to expr

View File

@@ -4,7 +4,7 @@ query predicate caseValues(CaseExpr c, Expr value) { value = c.getValue() }
query predicate caseNoValues(CaseExpr c) { not exists(c.getValue()) }
query predicate caseElseBranches(CaseExpr c, CaseElseBranch elseBranch) {
query predicate caseElseBranches(CaseExpr c, StmtSequence elseBranch) {
elseBranch = c.getElseBranch()
}

View File

@@ -333,6 +333,9 @@ pub fn extract(
.run_from_tree(&tree, source)
.unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}"));
traverse_yeast(&ast, &mut visitor);
// Comments and other `extra` nodes are not represented in the desugared
// AST, so recover them directly from the original parse tree.
traverse_extras(&tree, &mut visitor);
} else {
traverse(&tree, &mut visitor);
}
@@ -365,6 +368,8 @@ struct Visitor<'a> {
ast_node_parent_table_name: String,
/// Language-specific name of the tokeninfo table
tokeninfo_table_name: String,
/// Language-specific name of the trivia tokeninfo table
trivia_tokeninfo_table_name: String,
/// A lookup table from type name to node types
schema: &'a NodeTypeMap,
/// A stack for gathering information from child nodes. Whenever a node is
@@ -395,11 +400,33 @@ impl<'a> Visitor<'a> {
ast_node_location_table_name: format!("{language_prefix}_ast_node_location"),
ast_node_parent_table_name: format!("{language_prefix}_ast_node_parent"),
tokeninfo_table_name: format!("{language_prefix}_tokeninfo"),
trivia_tokeninfo_table_name: format!("{language_prefix}_trivia_tokeninfo"),
schema,
stack: Vec::new(),
}
}
/// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from
/// the original parse tree. Trivia tokens carry a location and their source
/// text, but are not attached to a parent in the (possibly desugared) AST.
fn emit_trivia_token(&mut self, node: &Node) {
let id = self.trap_writer.fresh_id();
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
self.trap_writer.add_tuple(
&self.ast_node_location_table_name,
vec![trap::Arg::Label(id), trap::Arg::Label(loc_label)],
);
self.trap_writer.add_tuple(
&self.trivia_tokeninfo_table_name,
vec![
trap::Arg::Label(id),
trap::Arg::Int(node.kind_id() as usize),
sliced_source_arg(self.source, node),
],
);
}
fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) {
self.diagnostics_writer.write(mesg);
let id = self.trap_writer.fresh_id();
@@ -835,6 +862,24 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) {
}
}
/// Walks the original tree-sitter tree and emits a `TriviaToken` for every
/// `extra` node (e.g. a comment). Used to preserve comments that would
/// otherwise be lost after a desugaring pass rewrites the tree.
fn traverse_extras(tree: &Tree, visitor: &mut Visitor) {
emit_extras_in(visitor, tree.root_node());
}
fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.is_extra() {
visitor.emit_trivia_token(&child);
} else {
emit_extras_in(visitor, child);
}
}
}
fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) {
use yeast::Cursor;
let mut cursor = tree.walk();

View File

@@ -68,7 +68,12 @@ pub fn generate(
let node_parent_table_name = format!("{}_ast_node_parent", &prefix);
let token_name = format!("{}_token", &prefix);
let tokeninfo_name = format!("{}_tokeninfo", &prefix);
let trivia_token_name = format!("{}_trivia_token", &prefix);
let trivia_tokeninfo_name = format!("{}_trivia_tokeninfo", &prefix);
let reserved_word_name = format!("{}_reserved_word", &prefix);
// When a desugaring is configured, comments and other `extra` nodes are
// preserved from the original parse tree as `TriviaToken`s.
let has_trivia_tokens = language.desugar.is_some();
let effective_node_types: String = match language
.desugar
.as_ref()
@@ -85,28 +90,35 @@ pub fn generate(
let nodes = node_types::read_node_types_str(&prefix, &effective_node_types)?;
let (dbscheme_entries, mut ast_node_members, token_kinds) = convert_nodes(&nodes);
ast_node_members.insert(&token_name);
if has_trivia_tokens {
ast_node_members.insert(&trivia_token_name);
}
writeln!(&mut dbscheme_writer, "/*- {} dbscheme -*/", language.name)?;
dbscheme::write(&mut dbscheme_writer, &dbscheme_entries)?;
let token_case = create_token_case(&token_name, token_kinds);
dbscheme::write(
&mut dbscheme_writer,
&[
dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)),
dbscheme::Entry::Case(token_case),
dbscheme::Entry::Union(dbscheme::Union {
name: &ast_node_name,
members: ast_node_members,
}),
dbscheme::Entry::Table(create_ast_node_location_table(
&node_location_table_name,
&ast_node_name,
)),
dbscheme::Entry::Table(create_ast_node_parent_table(
&node_parent_table_name,
&ast_node_name,
)),
],
)?;
let mut dbscheme_tail = vec![
dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)),
dbscheme::Entry::Case(token_case),
];
if has_trivia_tokens {
dbscheme_tail.push(dbscheme::Entry::Table(create_tokeninfo(
&trivia_tokeninfo_name,
&trivia_token_name,
)));
}
dbscheme_tail.push(dbscheme::Entry::Union(dbscheme::Union {
name: &ast_node_name,
members: ast_node_members,
}));
dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_location_table(
&node_location_table_name,
&ast_node_name,
)));
dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_parent_table(
&node_parent_table_name,
&ast_node_name,
)));
dbscheme::write(&mut dbscheme_writer, &dbscheme_tail)?;
let mut body = vec![
ql::TopLevel::Class(ql_gen::create_ast_node_class(
@@ -116,6 +128,12 @@ pub fn generate(
)),
ql::TopLevel::Class(ql_gen::create_token_class(&token_name, &tokeninfo_name)),
];
if has_trivia_tokens {
body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class(
&trivia_token_name,
&trivia_tokeninfo_name,
)));
}
// Only emit the ReservedWord class when there are actually unnamed token
// types in the schema (i.e., @{prefix}_reserved_word exists in the dbscheme).
// When converting from a YEAST YAML schema that has no unnamed tokens, this

View File

@@ -199,6 +199,70 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl
}
}
/// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are
/// `extra` nodes preserved from the original parse tree even when the tree has
/// been rewritten by a desugaring pass. They are not part of the regular
/// `Token` hierarchy because they do not appear in the (possibly desugared)
/// output schema.
pub fn create_trivia_token_class<'a>(
trivia_token_type: &'a str,
trivia_tokeninfo: &'a str,
) -> ql::Class<'a> {
let trivia_tokeninfo_arity = 3; // id, kind, value
let get_value = ql::Predicate {
qldoc: Some(String::from("Gets the source text of this trivia token.")),
name: "getValue",
overridden: false,
is_private: false,
is_final: true,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage(
"result",
trivia_tokeninfo,
1,
trivia_tokeninfo_arity,
),
overlay: None,
};
let to_string = ql::Predicate {
qldoc: Some(String::from(
"Gets a string representation of this element.",
)),
name: "toString",
overridden: true,
is_private: false,
is_final: true,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: ql::Expression::Equals(
Box::new(ql::Expression::Var("result")),
Box::new(ql::Expression::Dot(
Box::new(ql::Expression::Var("this")),
"getValue",
vec![],
)),
),
overlay: None,
};
ql::Class {
qldoc: Some(String::from(
"A trivia token, such as a comment, preserved from the original parse tree.",
)),
name: "TriviaToken",
is_abstract: false,
supertypes: vec![ql::Type::At(trivia_token_type), ql::Type::Normal("AstNode")]
.into_iter()
.collect(),
characteristic_predicate: None,
predicates: vec![
get_value,
to_string,
create_get_a_primary_ql_class("TriviaToken", false),
],
}
}
// Creates the `ReservedWord` class.
pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> {
let class_name = "ReservedWord";

View File

@@ -61,6 +61,18 @@ module Unified {
override string getAPrimaryQlClass() { result = "Token" }
}
/** A trivia token, such as a comment, preserved from the original parse tree. */
class TriviaToken extends @unified_trivia_token, AstNode {
/** Gets the source text of this trivia token. */
final string getValue() { unified_trivia_tokeninfo(this, _, result) }
/** Gets a string representation of this element. */
final override string toString() { result = this.getValue() }
/** Gets the name of the primary QL class for this element. */
override string getAPrimaryQlClass() { result = "TriviaToken" }
}
/** Gets the file containing the given `node`. */
private @file getNodeFile(@unified_ast_node node) {
exists(@location_default loc | unified_ast_node_location(node, loc) |

View File

@@ -0,0 +1,18 @@
/** Provides classes for working with comments. */
private import unified
/**
* A comment appearing in the source code.
*/
class Comment extends TriviaToken {
// At the moment, comments are the only type trivia token we extract
/**
* Gets the text inside this comment, not counting the delimeters.
*/
string getCommentText() {
result = this.getValue().regexpCapture("//(.*)", 1)
or
result = this.getValue().regexpCapture("(?s)/\\*(.*)\\*/", 1)
}
}

View File

@@ -334,7 +334,13 @@ case @unified_token.kind of
;
@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator
unified_trivia_tokeninfo(
unique int id: @unified_trivia_token,
int kind: int ref,
string value: string ref
);
@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_trivia_token | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator
unified_ast_node_location(
unique int node: @unified_ast_node ref,

View File

@@ -0,0 +1,8 @@
/**
* Provides classes for working with the AST, as well as files and locations.
*/
import codeql.Locations
import codeql.files.FileSystem
import codeql.unified.Ast::Unified
import codeql.unified.Comments

View File

@@ -0,0 +1,3 @@
| comments.swift:1:1:1:22 | // Hello this is swift | Hello this is swift |
| comments.swift:3:1:6:3 | /*\n * This is a multi-line comment\n * It should be ignored by the parser\n */ | \n * This is a multi-line comment\n * It should be ignored by the parser\n |
| comments.swift:9:5:9:36 | // This is a single-line comment | This is a single-line comment |

View File

@@ -0,0 +1,3 @@
import unified
query predicate comments(Comment c, string text) { text = c.getCommentText() }

View File

@@ -0,0 +1,11 @@
// Hello this is swift
/*
* This is a multi-line comment
* It should be ignored by the parser
*/
func hello() {
// This is a single-line comment
print("Hello, world!")
}