From 8e14c94e8b3f0ab8deecc3738a1b66fd028306c6 Mon Sep 17 00:00:00 2001
From: Tor Norbye
@@ -2298,7 +2298,7 @@
-This is for a program which is completely equivalent to the Java one.
+This program is equivalent to the Java one.
But notice that it has a completely different shape! They reference
different element classes, PsiClass
versus KtClass
, and on and on
all the way down.
@@ -2313,7 +2313,7 @@
-We can construct a new AST which represents the same concepts: +We can construct a new AST that represents the same concepts:
@@ -2337,7 +2337,7 @@
As you can see, the ASTs are not always identical. For Strings, in
-Kotlin, we often end up with an extra parent UiInjectionHost
. But for
+Kotlin, we often end up with an extra parent UInjectionHost
. But for
our purposes, you can see that the ASTs are mostly the same, so if you
handle the Kotlin scenario, you'll handle the Java ones too.
@@ -2348,7 +2348,7 @@
Note that “Unified” in the name here is a bit misleading. From the name
you may assume that this is some sort of superset of the ASTs across
-languages — and AST that can represent everything needed by all
+languages — an AST that can represent everything needed by all
languages. But that's not the case! Instead, a better way to think of it
is as the Java view of the AST.
@@ -2362,9 +2362,8 @@
)
This is a Kotlin data class with two properties. So you might expect
-that UAST would have a way to represent these concepts — properties,
-and java classes. This should be a UDataClass
with two UProperty
-children, right?
+that UAST would have a way to represent these concepts. This should
+be a UDataClass
with two UProperty
children, right?
@@ -2442,7 +2441,7 @@
-Every node in UAST is a subclass of a UElement. There's a parent
+Every node in UAST is a subclass of a UElement
. There's a parent
pointer, which is handy for navigating around in the AST.
@@ -2454,7 +2453,7 @@
-Or in the debugger, anytime you have a UElement, you can call
+Or in the debugger, anytime you have a UElement
, you can call
UElement.asRecursiveLogString
on it, evaluate and see what you find.
@@ -2488,7 +2487,7 @@
You generally shouldn't visit a source file on your own. Lint has a
-special UElementHandler
for that which is used to ensure that we don't
+special UElementHandler
for that, which is used to ensure we don't
repeat visiting a source file thousands of times, one per detector.
@@ -2538,7 +2537,7 @@
We have our UAST tree in the top right corner. And here's the Java PSI
AST behind the scenes. We can access the underlying PSI node for a
-UElement by accessing the sourcePsi element. So when you do need to dip
+UElement
by accessing the sourcePsi
property. So when you do need to dip
into something language specific, that's trivial to do.
@@ -2547,9 +2546,9 @@
-Each of the UElement nodes point back into the PSI AST - whether a Java
+Most UElement
nodes point back to the PSI AST - whether a Java
AST or a Kotlin AST. Here's the same AST, but with the type of the
-sourcePsi
attribute for each node added.
+sourcePsi
property for each node added.
@@ -2557,8 +2556,8 @@
-You can see that the class generated to represent the top level
-functions here doesn't have a non-null sourcePsi
, because in the
+You can see that the facade class generated to contain the top level
+functions has a null sourcePsi
, because in the
Kotlin PSI, there is no real KtClass
for a facade class. And for the
three members, the private field and the getter and the setter, they all
correspond to the exact same, single KtProperty
instance, the single
@@ -2596,8 +2595,8 @@
-There are lint checks which are language specific — for example, if -you write a lint check which forbids the use of companion objects — in +There are lint checks that are language specific — for example, if +you write a lint check that forbids the use of companion objects — in that case, there's no big advantage to using UAST over PSI; it's only ever going to run on Kotlin code. (Note however that lint's APIs and convenience callbacks are all targeting UAST, so it's easier to write @@ -2622,10 +2621,10 @@
For example, let's say you need to determine if a UClass
is a Kotlin
-“companion object“. You could cheat and look at the class name to see if
-it's ”Companion“. But that's not quite right; in Kotlin you can
+“companion object”. You could cheat and look at the class name to see if
+it's “Companion”. But that's not quite right; in Kotlin you can
specify a custom companion object name, and of course users are free
-to create classes named ”Companion“ that aren't companion objects:
+to create classes named “Companion” that aren't companion objects:
class Test {
companion object MyName { // Companion object not named "Companion"!
@@ -2635,8 +2634,8 @@
}
}
-The right way to do this, is using Kotlin PSI, via the
-UElement.sourcePsi
attribute:
+The right way to do this is using Kotlin PSI, via the
+UElement.sourcePsi
property:
// Skip companion objects
val source = node.sourcePsi
@@ -2645,7 +2644,7 @@
}
(To figure out how to write the above code, use a debugger on a test
-case and look at the UClass.sourcePsi
attribute; you'll discover that
+case and look at the UClass.sourcePsi
property; you'll discover that
it's some subclass of KtObjectDeclaration
; look up its most general
super interface or class, and then use code completion to discover
available APIs, such as isCompanion()
.)
@@ -2665,7 +2664,7 @@
Lint doesn't actually give you access to everything you need if you want
to try to look up types in Kotlin PSI; you need something called the
“binding context”, which is not exposed anywhere! And this omission is
-deliberate, because that was an implementation detail of the old
+deliberate, because this is an implementation detail of the old
compiler. The future is K2; a complete rewrite of the compiler front
end, which is no longer using the old binding context. And as part of
the tooling support for K2, there's a new API called the “Kotlin
@@ -2719,7 +2718,7 @@
Before the Kotlin lint analysis API, lint didn't have a way to reason
about the Nothing
type. UAST only returns Java types, which maps to
-void. So instead, lint had an ugly hack which just hardcoded well known
+void. So instead, lint had an ugly hack that just hardcoded well known
names of methods that don't return:
if (nextStatement is UCallExpression) {
@@ -2764,7 +2763,7 @@
-Similarly on a KtDeclaration
(such as a named function or property) I
+Similarly, on a KtDeclaration
(such as a named function or property) I
can call getSymbol()
to get the symbol for that method or property, to
for example look up parameter information. And on a KtExpression
(such
as an if statement) I can call getKtType()
to get the Kotlin type.
@@ -2779,7 +2778,7 @@
In the new implementation of callNeverReturns
, we resolve the call,
-look up the corresponding function which of course is a KtSymbol
+look up the corresponding function, which of course is a KtSymbol
itself, and from that we get the return type, and then we can just check
if it's the Nothing
type.
diff --git a/docs/api-guide/ast-analysis.md.html b/docs/api-guide/ast-analysis.md.html
index 5cf2478d..167013d4 100644
--- a/docs/api-guide/ast-analysis.md.html
+++ b/docs/api-guide/ast-analysis.md.html
@@ -42,7 +42,7 @@
Anyway, you can see there is quite a bit of detail here -- tracking
things like the keywords, the variables, references to for example the
-package -- and higher level concepts like a class and a field which I've
+package -- and higher level concepts like a class and a field, which I've
marked with a thicker border.
Here's the corresponding Kotlin program:
@@ -60,7 +60,7 @@
![](images/kotlin-psi.png)
-This is for a program which is completely equivalent to the Java one.
+This program is equivalent to the Java one.
But notice that it has a completely different shape! They reference
different element classes, `PsiClass` versus `KtClass`, and on and on
all the way down.
@@ -70,7 +70,7 @@
## UAST
-We can construct a new AST which represents the same concepts:
+We can construct a new AST that represents the same concepts:
![](images/uast-java.png)
@@ -84,7 +84,7 @@
![](images/uast-kotlin.png)
As you can see, the ASTs are not always identical. For Strings, in
-Kotlin, we often end up with an extra parent `UiInjectionHost`. But for
+Kotlin, we often end up with an extra parent `UInjectionHost`. But for
our purposes, you can see that the ASTs are mostly the same, so if you
handle the Kotlin scenario, you'll handle the Java ones too.
@@ -92,7 +92,7 @@
Note that “Unified” in the name here is a bit misleading. From the name
you may assume that this is some sort of superset of the ASTs across
-languages -- and AST that can represent everything needed by all
+languages -- an AST that can represent everything needed by all
languages. But that's not the case! Instead, a better way to think of it
is as the **Java view** of the AST.
@@ -106,9 +106,8 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is a Kotlin data class with two properties. So you might expect
-that UAST would have a way to represent these concepts -- properties,
-and java classes. This should be a `UDataClass` with two `UProperty`
-children, right?
+that UAST would have a way to represent these concepts. This should
+be a `UDataClass` with two `UProperty` children, right?
But Java doesn't support properties. If you try to access a `Person`
instance from Java, you'll notice that it exposes a number of public
@@ -166,7 +165,7 @@
## UElement
-Every node in UAST is a subclass of a UElement. There's a parent
+Every node in UAST is a subclass of a `UElement`. There's a parent
pointer, which is handy for navigating around in the AST.
The real skill you need for writing lint checks is understanding the
@@ -174,7 +173,7 @@
is to create the Kotlin or Java code you want, in a unit test, and then
in your detector, recursively print out the UAST as a tree.
-Or in the debugger, anytime you have a UElement, you can call
+Or in the debugger, anytime you have a `UElement`, you can call
`UElement.asRecursiveLogString` on it, evaluate and see what you find.
For example, for the following Kotlin code:
@@ -209,7 +208,7 @@
## Visiting
You generally shouldn't visit a source file on your own. Lint has a
-special `UElementHandler` for that which is used to ensure that we don't
+special `UElementHandler` for that, which is used to ensure we don't
repeat visiting a source file thousands of times, one per detector.
But when you're doing local analysis, you sometimes need to visit a
@@ -246,19 +245,19 @@
We have our UAST tree in the top right corner. And here's the Java PSI
AST behind the scenes. We can access the underlying PSI node for a
-UElement by accessing the sourcePsi element. So when you do need to dip
+`UElement` by accessing the `sourcePsi` property. So when you do need to dip
into something language specific, that's trivial to do.
Note that in some cases, these references are null.
-Each of the UElement nodes point back into the PSI AST - whether a Java
+Most `UElement` nodes point back to the PSI AST - whether a Java
AST or a Kotlin AST. Here's the same AST, but with the **type** of the
-`sourcePsi` attribute for each node added.
+`sourcePsi` property for each node added.
![](images/uast-sourcepsi-type.png)
-You can see that the class generated to represent the top level
-functions here doesn't have a non-null `sourcePsi`, because in the
+You can see that the facade class generated to contain the top level
+functions has a null `sourcePsi`, because in the
Kotlin PSI, there is no real `KtClass` for a facade class. And for the
three members, the private field and the getter and the setter, they all
correspond to the exact same, single `KtProperty` instance, the single
@@ -288,8 +287,8 @@
across the languages. Declarations. Function calls. Super classes.
Assignments. If expressions. Return statements. And on and on.
-There *are* lint checks which are language specific -- for example, if
-you write a lint check which forbids the use of companion objects -- in
+There *are* lint checks that are language specific -- for example, if
+you write a lint check that forbids the use of companion objects -- in
that case, there's no big advantage to using UAST over PSI; it's only
ever going to run on Kotlin code. (Note however that lint's APIs and
convenience callbacks are all targeting UAST, so it's easier to write
@@ -308,10 +307,10 @@
language specific, and where the language details aren't exposed in UAST.
For example, let's say you need to determine if a `UClass` is a Kotlin
-"companion object“. You could cheat and look at the class name to see if
-it's ”Companion“. But that's not quite right; in Kotlin you can
+“companion object”. You could cheat and look at the class name to see if
+it's “Companion”. But that's not quite right; in Kotlin you can
specify a custom companion object name, and of course users are free
-to create classes named ”Companion“ that aren't companion objects:
+to create classes named “Companion” that aren't companion objects:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin
class Test {
@@ -323,8 +322,8 @@
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The right way to do this, is using Kotlin PSI, via the
-`UElement.sourcePsi` attribute:
+The right way to do this is using Kotlin PSI, via the
+`UElement.sourcePsi` property:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin
// Skip companion objects
@@ -335,7 +334,7 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(To figure out how to write the above code, use a debugger on a test
-case and look at the `UClass.sourcePsi` attribute; you'll discover that
+case and look at the `UClass.sourcePsi` property; you'll discover that
it's some subclass of `KtObjectDeclaration`; look up its most general
super interface or class, and then use code completion to discover
available APIs, such as `isCompanion()`.)
@@ -350,7 +349,7 @@
Lint doesn't actually give you access to everything you need if you want
to try to look up types in Kotlin PSI; you need something called the
"binding context”, which is not exposed anywhere! And this omission is
-deliberate, because that was an implementation detail of the old
+deliberate, because this is an implementation detail of the old
compiler. The future is K2; a complete rewrite of the compiler front
end, which is no longer using the old binding context. And as part of
the tooling support for K2, there's a new API called the “Kotlin
@@ -398,7 +397,7 @@
Before the Kotlin lint analysis API, lint didn't have a way to reason
about the `Nothing` type. UAST only returns Java types, which maps to
-void. So instead, lint had an ugly hack which just hardcoded well known
+void. So instead, lint had an ugly hack that just hardcoded well known
names of methods that don't return:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin
@@ -441,7 +440,7 @@
Here, we have a `KtCallExpression`, and inside the `analyze` block we
can call `resolveCall()` on it to reach the called method's symbol.
-Similarly on a `KtDeclaration` (such as a named function or property) I
+Similarly, on a `KtDeclaration` (such as a named function or property) I
can call `getSymbol()` to get the symbol for that method or property, to
for example look up parameter information. And on a `KtExpression` (such
as an if statement) I can call `getKtType()` to get the Kotlin type.
@@ -452,7 +451,7 @@
so on.
In the new implementation of `callNeverReturns`, we resolve the call,
-look up the corresponding function which of course is a `KtSymbol`
+look up the corresponding function, which of course is a `KtSymbol`
itself, and from that we get the return type, and then we can just check
if it's the `Nothing` type.
diff --git a/docs/changes.md.html b/docs/changes.md.html
index b8f9f5ab..e3443260 100644
--- a/docs/changes.md.html
+++ b/docs/changes.md.html
@@ -12,6 +12,8 @@
## Documentation Changes
+2024/07/02: New documentation on AST analysis and the Kotlin Analysis API
+
2022/06/29: Added documentation on how to write error messages, and fixed a bug
which had left chapters 7-11 missing from the api-guide (the chapters on
partial analysis, the dataflow analyzer, annotations and options).
diff --git a/docs/index.html b/docs/index.html
index cb82870c..3719b1e8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -87,6 +87,8 @@
Analyzing data flow
Publishing a Lint check
+
+ AST Analysis
Unit Testing
@@ -155,4 +157,4 @@
-