Skip to content

Commit cdf3d47

Browse files
committed
C#: Copy dotnet.Element implementation.
1 parent c606ab0 commit cdf3d47

File tree

1 file changed

+143
-5
lines changed

1 file changed

+143
-5
lines changed

csharp/ql/lib/semmle/code/csharp/Element.qll

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import Location
66
private import semmle.code.csharp.ExprOrStmtParent
7-
private import dotnet
87
private import commons.QualifiedName
98

109
/**
@@ -14,18 +13,64 @@ private import commons.QualifiedName
1413
* (`NamespaceDeclaration`), a `using` directive (`UsingDirective`), or type
1514
* parameter constraints (`TypeParameterConstraints`).
1615
*/
17-
class Element extends DotNet::Element, @element {
18-
override string toStringWithTypes() { result = this.toString() }
16+
class Element extends @element {
17+
/** Gets a textual representation of this element. */
18+
cached
19+
string toString() { none() }
20+
21+
/** Gets the file containing this element. */
22+
final File getFile() { result = this.getLocation().getFile() }
23+
24+
/** Holds if this element is from source code. */
25+
predicate fromSource() { this.getFile().fromSource() }
26+
27+
/** Holds if this element is from an assembly. */
28+
predicate fromLibrary() { this.getFile().fromLibrary() }
29+
30+
/**
31+
* Gets the "language" of this program element, as defined by the extension of the filename.
32+
* For example, C# has language "cs", and Visual Basic has language "vb".
33+
*/
34+
final string getLanguage() { result = this.getLocation().getFile().getExtension() }
35+
36+
/**
37+
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
38+
*
39+
* If no primary class can be determined, the result is `"???"`.
40+
*/
41+
final string getPrimaryQlClasses() {
42+
result = strictconcat(this.getAPrimaryQlClass(), ",")
43+
or
44+
not exists(this.getAPrimaryQlClass()) and
45+
result = "???"
46+
}
47+
48+
/**
49+
* Gets the name of a primary CodeQL class to which this element belongs.
50+
*
51+
* For most elements, this is simply the most precise syntactic category to
52+
* which they belong; for example, `AddExpr` is a primary class, but
53+
* `BinaryOperation` is not.
54+
*
55+
* If no primary classes match, this predicate has no result. If multiple
56+
* primary classes match, this predicate can have multiple results.
57+
*
58+
* See also `getPrimaryQlClasses`, which is better to use in most cases.
59+
*/
60+
string getAPrimaryQlClass() { none() }
61+
62+
/** Gets the full textual representation of this element, including type information. */
63+
string toStringWithTypes() { result = this.toString() }
1964

2065
/**
2166
* Gets the location of this element. Where an element has locations in
2267
* source and assemblies, choose the source location. If there are multiple
2368
* assembly locations, choose only one.
2469
*/
25-
final override Location getLocation() { result = bestLocation(this) }
70+
final Location getLocation() { result = bestLocation(this) }
2671

2772
/** Gets a location of this element, including sources and assemblies. */
28-
override Location getALocation() { none() }
73+
Location getALocation() { none() }
2974

3075
/** Gets the parent of this element, if any. */
3176
Element getParent() { result.getAChild() = this }
@@ -46,3 +91,96 @@ class Element extends DotNet::Element, @element {
4691
*/
4792
int getIndex() { exists(Element parent | parent.getChild(result) = this) }
4893
}
94+
95+
/** An element that has a name. */
96+
class NamedElement extends Element, @named_element {
97+
/** Gets the name of this element. */
98+
cached
99+
string getName() { none() }
100+
101+
/** Holds if this element has name 'name'. */
102+
final predicate hasName(string name) { name = this.getName() }
103+
104+
/**
105+
* Gets the fully qualified name of this element, for example the
106+
* fully qualified name of `M` on line 3 is `N.C.M` in
107+
*
108+
* ```csharp
109+
* namespace N {
110+
* class C {
111+
* void M(int i, string s) { }
112+
* }
113+
* }
114+
* ```
115+
*/
116+
cached
117+
deprecated final string getQualifiedName() {
118+
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
119+
if qualifier = "" then result = name else result = qualifier + "." + name
120+
)
121+
}
122+
123+
/**
124+
* Gets the fully qualified name of this element, for example the
125+
* fully qualified name of `M` on line 3 is `N.C.M` in
126+
*
127+
* ```csharp
128+
* namespace N {
129+
* class C {
130+
* void M(int i, string s) { }
131+
* }
132+
* }
133+
* ```
134+
*
135+
* Unbound generic types, such as `IList<T>`, are represented as
136+
* ``System.Collections.Generic.IList`1``.
137+
*/
138+
cached
139+
final string getFullyQualifiedName() {
140+
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
141+
if qualifier = "" then result = name else result = qualifier + "." + name
142+
)
143+
}
144+
145+
/**
146+
* DEPRECATED: Use `hasFullyQualifiedName` instead.
147+
*
148+
* Holds if this element has the qualified name `qualifier`.`name`.
149+
*/
150+
cached
151+
deprecated predicate hasQualifiedName(string qualifier, string name) {
152+
qualifier = "" and name = this.getName()
153+
}
154+
155+
/** Holds if this element has the fully qualified name `qualifier`.`name`. */
156+
cached
157+
predicate hasFullyQualifiedName(string qualifier, string name) {
158+
qualifier = "" and name = this.getName()
159+
}
160+
161+
/** Gets a unique string label for this element. */
162+
cached
163+
string getLabel() { none() }
164+
165+
/** Holds if `other` has the same metadata handle in the same assembly. */
166+
predicate matchesHandle(NamedElement other) {
167+
exists(Assembly asm, int handle |
168+
metadata_handle(this, asm, handle) and
169+
metadata_handle(other, asm, handle)
170+
)
171+
}
172+
173+
/**
174+
* Holds if this element was compiled from source code that is also present in the
175+
* database. That is, this element corresponds to another element from source.
176+
*/
177+
predicate compiledFromSource() {
178+
not this.fromSource() and
179+
exists(NamedElement other | other != this |
180+
this.matchesHandle(other) and
181+
other.fromSource()
182+
)
183+
}
184+
185+
override string toString() { result = this.getName() }
186+
}

0 commit comments

Comments
 (0)